首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >与$elemMatch一起使用多个标准

与$elemMatch一起使用多个标准
EN

Stack Overflow用户
提问于 2014-03-28 22:27:03
回答 1查看 2.1K关注 0票数 0

我有一份蒙古文件,里面有一份物品清单。这些项目中的每一个都有一些与其相关的状态。

我希望使用$elemMatch返回具有符合某些条件的状态的文档。

请考虑以下文件。它代表一个订单,而顺序中的每个项目都不同(它们代表眼镜):

代码语言:javascript
复制
{
    "_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

但是,我的查询确实返回了这个文档!

以下是我的疑问:

代码语言:javascript
复制
{
    "$and": [
        {
            "items": {
                "$elemMatch": {
                    "lens_type": {
                       "$in": [
                            "STANDARD_INDEX_LENS",
                            "RX_SUN_LENS"
                        ]
                    },
                    "status.received_from_lab": {"$exists": true}
                }
            }
        },
        {
            "items": {
                "$elemMatch": {
                    "status.shipped": {"$exists": false}
                }
            }
        }
    ]
}

我的查询中的逻辑错误是什么?我应该使用什么构造来代替?我需要在客户端进行这种过滤吗?

EN

回答 1

Stack Overflow用户

发布于 2014-03-29 02:38:21

逻辑的问题是,给定文档,带有"STANDARD_INDEX_LENS“的类型与第二个条件匹配,匹配"RX_SUN_LENS”的项匹配第一个条件。因此,由于都是真的,所以将返回文档。

你没有做的是说,你的“处方”镜片可以有任何一种情况评估。因此,写这篇文章最简单的方法可能如下:

代码语言:javascript
复制
{
    "$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()来做到这一点:

代码语言:javascript
复制
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方法应该适合您的需要,但至少您有一些需要尝试的地方。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22724233

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档