
您需要在此处“投影”匹配项,因为所有MongoDB查询所做的都是查找“文档”,该“文档”具有 “至少一个”元素 ,且 “大于” 您所要求的条件。
因此,过滤“数组”与您拥有的“查询”条件不同。
一个简单的“投影”将使“第一个”匹配项返回该条件。因此,这可能不是您想要的,但例如:
Order.find({ "articles.quantity": { "$gte": 5 } }) .select({ "articles.$": 1 }) .populate({ "path": "articles.article", "match": { "price": { "$lte": 500 } } }).exec(function(err,orders) { // populated and filtered twice })那种“排序”可以满足您的需求,但问题实际上将是,数组中最多只能返回 一个 元素
"articles"。
要正确执行此 *** 作,您需要
.aggregate()过滤数组内容。理想情况下,这是通过MongoDB
3.2和
$filter。但是这里还有一种特殊的方法
.populate():
Order.aggregate( [ { "$match": { "artciles.quantity": { "$gte": 5 } } }, { "$project": { "orderdate": 1, "articles": { "$filter": { "input": "$articles", "as": "article", "cond": { "$gte": [ "$$article.quantity", 5 ] } } }, "__v": 1 }} ], function(err,orders) { Order.populate( orders.map(function(order) { return new Order(order) }), { "path": "articles.article", "match": { "price": { "$lte": 500 } } }, function(err,orders) { // now it's all populated and mongoose documents } ) })因此,这里发生的是
.aggregate()语句中实际发生的数组“过滤”
,但是当然,此 *** 作的结果不再是“猫鼬文档”,因为它的一个方面
.aggregate()是它可以“更改”文档结构,并且因此,猫鼬“假定”是这种情况,并且仅返回“普通对象”。
这并不是真正的问题,因为当您看到
$project阶段时,我们实际上是在根据定义的模式要求文档中存在的所有相同字段。因此,即使它只是一个“普通对象”,也没有问题将其“投射”回猫鼬文档中。
这是
.map()进来的地方,因为它返回一个转换后的“文档”数组,这对于下一阶段很重要。
现在调用
Model.populate(),然后可以在“猫鼬文档数组”上运行其他“填充”。
结果最终就是您想要的。
MongoDB低于3.2.x的版本
唯一真正改变的是聚合管道,因此,为了简洁起见,所有这些都需要包括在内。
MongoDB 2.6-
可以使用
$map和组合过滤数组
$setDifference。结果是一个“集合”,但是当猫鼬
_id默认情况下在所有子文档数组上创建一个字段时,这不是问题:
[ { "$match": { "artciles.quantity": { "$gte": 5 } } }, { "$project": { "orderdate": 1, "articles": { "$setDiffernce": [ { "$map": {"input": "$articles","as": "article","in": { "$cond": [ { "$gte": [ "$$article.price", 5 ] }, "$$article", false ]} }}, [false] ] }, "__v": 1 }} ],的旧版本必须使用
$unwind:
[ { "$match": { "artciles.quantity": { "$gte": 5 } }}, { "$unwind": "$articles" }, { "$match": { "artciles.quantity": { "$gte": 5 } }}, { "$group": { "_id": "$_id", "orderdate": { "$first": "$orderdate" }, "articles": { "$push": "$articles" }, "__v": { "$first": "$__v" } }} ],$ lookup替代另一种替代方法是只在“服务器”上执行所有 *** 作。这是
$lookupMongoDB
3.2及更高版本的选项:
Order.aggregate( [ { "$match": { "artciles.quantity": { "$gte": 5 } }}, { "$project": { "orderdate": 1, "articles": { "$filter": { "input": "$articles", "as": "article", "cond": { "$gte": [ "$$article.quantity", 5 ] } } }, "__v": 1 }}, { "$unwind": "$articles" }, { "$lookup": { "from": "articles", "localField": "articles.article", "foreignField": "_id", "as": "articles.article" }}, { "$unwind": "$articles.article" }, { "$group": { "_id": "$_id", "orderdate": { "$first": "$orderdate" }, "articles": { "$push": "$articles" }, "__v": { "$first": "$__v" } }}, { "$project": { "orderdate": 1, "articles": { "$filter": { "input": "$articles", "as": "article", "cond": { "$lte": [ "$$article.article.price", 500 ] } } }, "__v": 1 }} ], function(err,orders) { })尽管这些只是简单的文档,但其结果与您从该
.populate()方法中获得的结果相同。当然,如果确实需要,在所有情况下,您都可以随时再次再次“广播”到猫鼬文档中。“最短”路径
这实际上可以追溯到原始语句,在该语句中,您基本上只是“接受”“查询”并不是要“过滤”数组内容。该
.populate()可happilly这样做becuse它只是一个“查询”,并在方便的“文档”馅。
因此,如果您真的没有通过删除原始文档数组中的其他数组成员来节省带宽的“负担”,那么请
.filter()在后期处理代码中将它们删除:
Order.find({ "articles.quantity": { "$gte": 5 } }) .populate({ "path": "articles.article", "match": { "price": { "$lte": 500 } } }).exec(function(err,orders) { orders = orders.filter(function(order) { order.articles = order.articles.filter(function(article) { return ( ( article.quantity >= 5 ) && ( article.article != null ) ) }); return order.aricles.length > 0; }) // orders has non matching entries removed })欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)