【问题标题】:MongoDB elemMatch does not work expectedMongoDB elemMatch 无法正常工作
【发布时间】:2014-11-23 19:52:55
【问题描述】:

我正在尝试获取符合我的条件的子文档。

我的 MongoDB 查询是这样的:

db.SCSIssue.find(
 { _id: ObjectId("5439a2992ea8cc0f70feef2d") }, 
 { Statuses: { $elemMatch: { StatusID: { $gte : NumberLong(521055087020736513) } } } }
)

我的架构是这样的:

{
    ....
    "_id": ObjectId("5439a2992ea8cc0f70feef2d"),
    ....
    "Statuses": [{
        ....
        "StatusID": NumberLong(525623822633172993),
    },{
        ....
        "StatusID": NumberLong(521055087020736513),
    },{
        ....
        "StatusID": NumberLong(521060802959532033),
    }]
    ....
},
{
    ....
    "_id": ObjectId("543c04662ea8cd11ec4dda5f"),
    ....
    "Statuses": [{
        ....
        "StatusID": NumberLong(535623822633172993),
    },{
        ....
        "StatusID": NumberLong(541055087020736513),
    },{
        ....
        "StatusID": NumberLong(551060802959532033),
    }]
    ....
},
....

查询结果:

{
    "_id" : ObjectId("5439a2992ea8cc0f70feef2d"),
    "Statuses" : [{
        ....
        "StatusID": NumberLong(525623822633172993),
        ....
    }]
}

预期结果:

{
    "_id" : ObjectId("5439a2992ea8cc0f70feef2d"),
    "Statuses" : [{
        ....
        "StatusID": NumberLong(521055087020736513),
    },{
        ....
        "StatusID": NumberLong(521060802959532033),
    }]
}

简而言之,我想在数组(状态)中获取大于或等于我的条件且 _id 等于我的条件的相同时间的子文档。我已经阅读了很多关于此的答案。他们都喜欢我的问题,但在我的情况下,它不会起作用。

我错过了什么? 谢谢你。

【问题讨论】:

    标签: mongodb mongodb-query


    【解决方案1】:

    $elemMatch 的行为并没有错。它按预期工作。文档还说:

    但是,$elemMatch 投影仅返回第一个匹配项 数组中的元素。

    根据经验,每当您使用$elemMatch 投影array 时,最多只能投影一个元素。如果数组中没有任何元素匹配,则根本不会投影该字段。

    所以你得到的结果是正确的,只有数组中与$elemMatch中的条件匹配的第一项才会是projected

    {
        "_id" : ObjectId("5439a2992ea8cc0f70feef2d"),
        "Statuses" : [{
            ....
            "StatusID": NumberLong(525623822633172993),
            ....
        }]
    }
    

    您可以尝试更改 statuses 数组中文档的顺序,如果该文档出现在数组中其他匹配文档之前,则可能会得到不同的匹配文档。

    参考:$elemMatch

    根据您的要求,如果您想要结果中的所有匹配数组元素,则需要执行聚合操作。

    • Match 具有所需_id 的那些文件和那些文件 其中包含我们正在搜索的状态子文档。
    • unwind 状态数组。
    • 再次match 单个展开的文档。
    • 最后group_id匹配的文档。

    代码:

    db.collection.aggregate([
    {$match:{ "_id": ObjectId("5439a2992ea8cc0f70feef2d"),
              "Statuses.StatusID":{$gte : NumberLong(525623822633172993)}}},
    {$unwind:"$Statuses"},
    {$match:{"Statuses.StatusID":{$gte : NumberLong(525623822633172993)}}},
    {$group:{"_id":"$_id",statuses:{$push:"$Statuses"}}}
    ])
    

    这将为您提供数组中所有匹配的子文档。

    【讨论】:

    • 感谢您的回答。关于您的查询,我还有一个问题。为什么要使用“Statuses.StatusID”匹配两次?有什么技巧吗?
    • 如果文档没有匹配statusId的状态子文档,在初始匹配操作阶段添加条件可以防止以下不必要的展开和匹配操作。
    【解决方案2】:

    仅供参考 find 方法有 2 个参数,第一个是要发送到数据库的查询,第二个是投影。 当您进行搜索时,您将发送此 ...find({query},{projection})

    db.SCSIssue.find(
    { _id: ObjectId("5439a2992ea8cc0f70feef2d") }, 
    { Statuses: { $elemMatch: { StatusID: { $gte : NumberLong(521055087020736513)}}}})
    

    您可能想要做的是在 find 方法的查询部分中完成所有操作。

    db.SCSIssue.find(
    { _id: ObjectId("5439a2992ea8cc0f70feef2d"), 
       Statuses: { $elemMatch: { StatusID: { $gte : NumberLong(521055087020736513)}},
       xxxxx <- second param for the projection part
    )
    

    【讨论】:

      猜你喜欢
      • 2019-08-30
      • 2018-03-10
      • 2023-03-29
      • 2020-10-20
      • 2021-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多