2014-11-23 120 views
1

我想获取符合我的条件的子文档。MongoDB elemMatch不能正常工作

我的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等于我的条件。我读了很多关于这个的答案。他们都喜欢我的问题,但在我的情况下,它没有预期的工作。

我错过了什么? 谢谢。

回答

0

$elemMatch的行为没有任何问题。它按预期工作。该文档还说:

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

作为一个经验法则,只要你投影array使用$elemMatch只有一个元素将被投影最多。如果数组中没有任何元素匹配,则该字段根本不会投影。

因此,您得到的结果是正确的,只有匹配$elemMatch中条件的数组中的第一项将是projected

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

您可以尝试改变的状态数组中文档的顺序,如果该文件出现提前阵列中的其它匹配的文件可能会得到不同的匹配文档。

参见:$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"}}} 
]) 

,这将给你阵列中所有匹配的子文件。

+0

谢谢你的回答。我还有一个关于你的查询的问题。为什么你使用“Statuses.StatusID”匹配两次?有什么技巧吗? – Dreamcatcher 2014-11-24 20:44:32

+0

在初始匹配操作阶段添加条件将防止以下不必要的展开和匹配操作符,如果文档没有具有匹配的statusId的状态子文档。 – BatScream 2014-11-24 21:09:35