我有一份蒙古文件,里面有一份物品清单。这些项目中的每一个都有一些与其相关的状态。
我希望使用$elemMatch返回具有符合某些条件的状态的文档。
请考虑以下文件。它代表一个订单,而顺序中的每个项目都不同(它们代表眼镜):
{
"_id" : ObjectId("5335dcd6888a4f21dd77657c"),
"items" : [
{
"lens_type" : "STANDARD_INDEX_LENS",
"status" : {}
},
{
"lens_type" : "NO_LENS",
"status" : {
"shipped" : true
}
},
{
"lens_type" : "RX_SUN_LENS",
"status" : {
"received_from_lab" : true,
"sent_to_lab" : true,
"shipped" : true
}
}
]
}我想找到所有的项目,是“未发货”-即,items.status.shipped不存在。我想找到所有准备装运的物品。
然而,如果这个项目有一个处方镜头-- lens_type或者是STANDARD_INDEX_LENS或者RX_SUN_LENS --那么我只认为它是从实验室收到的未发货的。item.status.received_from_lab存在。
以上文档不应由我的查询返回。这是因为其中两个项目已经发货,而另一个项目还没有发货,但还不是received_from_lab。
但是,我的查询确实返回了这个文档!
以下是我的疑问:
{
"$and": [
{
"items": {
"$elemMatch": {
"lens_type": {
"$in": [
"STANDARD_INDEX_LENS",
"RX_SUN_LENS"
]
},
"status.received_from_lab": {"$exists": true}
}
}
},
{
"items": {
"$elemMatch": {
"status.shipped": {"$exists": false}
}
}
}
]
}我的查询中的逻辑错误是什么?我应该使用什么构造来代替?我需要在客户端进行这种过滤吗?
发布于 2014-03-29 02:38:21
逻辑的问题是,给定文档,带有"STANDARD_INDEX_LENS“的类型与第二个条件匹配,匹配"RX_SUN_LENS”的项匹配第一个条件。因此,由于和都是真的,所以将返回文档。
你没有做的是说,你的“处方”镜片可以有任何一种情况评估。因此,写这篇文章最简单的方法可能如下:
{
"$and": [
{
"items": {
"$elemMatch": {
"lens_type": {
"$in": [
"STANDARD_INDEX_LENS",
"RX_SUN_LENS"
]
},
"status.received_from_lab": {"$exists": true}
}
}
},
{
"items": {
"$elemMatch": {
"lens_type": {
"$nin": [
"STANDARD_INDEX_LENS",
"RX_SUN_LENS"
]
},
"status.shipped": {"$exists": false}
}
}
}
]
}因此,那里的$nin操作符确保在检查“已发送”状态时,检查不会在“处方”类型上执行,而只在其他项目上执行,因此不能对其中一个“处方”进行评估。
正如我说过的,如果你认为你的逻辑在这个限制中更加复杂的话,还有另一种方法。因此,您需要一种将条件应用于数组中元素的所有的方法。您可以使用.aggregate()来做到这一点:
db.order.aggregate([
// Document level filtering still makes sense
{ "$match": {
"$and": [
{
"items": {
"$elemMatch": {
"lens_type": {
"$in": [
"STANDARD_INDEX_LENS",
"RX_SUN_LENS"
]
},
"status.received_from_lab": {"$exists": true}
}
}
},
{
"items": {
"$elemMatch": {
"status.shipped": {"$exists": false}
}
}
}
]
}},
// Unwind to de-normalize
{ "$unwind": "$items" },
// Then actually "filter" each of the un-wound documents
{ "$match": {
"$and": [
{
"items.lens_type": {
"$in": [
"STANDARD_INDEX_LENS",
"RX_SUN_LENS"
]
},
"items.status.received_from_lab": {"$exists": true}
},
{
"items.status.shipped": {"$exists": false}
}
]
}}
// Group back the results of any found "elements"
{ "$group": {
"_id": "$_id",
"items": { "$push": "$items" }
}}
])因此,这基本上是在执行初始$match之后,数组中的文档被“拆分”,或者通常使用$unwind“非规范化”,因此它们现在出现在单独的文档本身中。
然后,附加的$match确保所剩的任何内容都不符合这些条件。或者您可能希望将逻辑更改为另一种情况。最后,可以使用$group将任何结果带回到数组中。但是这个数组将只包含未被过滤的文档。所以文件的形式会被改变。
您可以使用显示here的技术“保留”原始文档的形式。
但这“取决于”你的需求是什么。看起来,first方法应该适合您的需要,但至少您有一些需要尝试的地方。
https://stackoverflow.com/questions/22724233
复制相似问题