4

在 MongoDB 的新版本中,我们可以使用 $elemMatch 投影运算符将查询的响应限制为数组的单个匹配元素。http://docs.mongodb.org/manual/reference/projection/elemMatch/

但它似乎在 mongoose 3 中还不起作用,这是示例:

{
 _id: ObjectId(5), 
 items: [1,2,3,45,4,67,9,4]
}

Folder.findOne({_id: Object(5)}, {$elemMatch: {$in: [1,67,9]}})
  .exec(function (err, doc) {

});

我预计会得到以下文档:

{
 _id: ObjectId(5), 
 items: [1,67,9]
}

但不幸的是,我得到的是包含所有项目的文档:

{
 _id: ObjectId(5), 
 items: [1,2,3,45,4,67,9,4]
}
4

4 回答 4

4

这里的 mongodb 文档具有误导性,我们将对其进行更新。

它的意思是您现在可以在投影中使用 $elemMatch ,即您的字段选择:

https://gist.github.com/3640687

另见:https ://github.com/learnboost/mongoose/issues/1085

[编辑] 对已发送文档的拉取请求:https ://github.com/mongodb/docs/pull/185

于 2012-09-05T17:35:29.973 回答
2

首先,您缺少items$elemMatch 运算符前面的字段名称。您的查询应为

Folder.findOne({_id: Object(5)}, {items: {$elemMatch: {$in: [1,67,9]}}})
  .exec(function (err, doc) { });

但这仍然不会返回所需的结果,因为如文档中所述:

$elemMatch 投影将仅匹配每个源文档的一个数组元素。

所以你只会得到类似的东西:

{
 _id: ObjectId(5), 
 items: [1]
}
于 2012-09-05T05:50:11.427 回答
1

我没有设置 mongoose 来使用节点执行此操作,但您也可以使用 2.2 中的新聚合框架获得您想要的结果 - 这是一个可以为您提供所需结果的示例。首先,我的示例文档如下所示:

> db.foo.findOne()
{
    "_id" : ObjectId("50472eb566caf6af6108de02"),
    "items" : [
        1,
        2,
        3,
        45,
        4,
        67,
        9,
        4
    ]
}

为了达到你想要的,我这样做了:

> db.foo.aggregate( 
             {$match : {"_id": ObjectId("50472eb566caf6af6108de02")}},  
             {$unwind : "$items"},  
             {$match : {"items": {$in : [1, 67, 9]}}},  
             {$group : {_id : "$_id", items : { $push : "$items"}}},
             {$project : {_id : 0, items : 1}}
     )
{
    "result" : [
    {
        "_id" : ObjectId("50472eb566caf6af6108de02"),
        "items" : [
            1,
            67,
            9
        ]
    }
],
"ok" : 1

}

为了解释,我将逐行详细说明:

{$match : {"_id": ObjectId("50472eb566caf6af6108de02")}}

这是相当明显的——它基本上等同于常规查询的查找条件,结果被传递到管道中的下一步进行处理。这是可以使用索引等的部分。

{$unwind : "$items"}

这将爆炸数组,创建一个文档流,数组的每个元素都有一个。

{$match : {"items": {$in : [1, 67, 9]}}}

第二个匹配将只返回列表中的文档,基本上将文档流减少到三个结果集。

{$group : {_id : "$_id", items : { $push : "$items"}}}

我们希望我们的输出是一个数组,所以我们必须撤消上面的展开,因为我们已经选择了我们想要的项目,使用 _id 作为分组的键。注意:如果有多个匹配项,这将具有重复值,如果您想要一个唯一列表,您将使用$addToSet而不是$push

{$project : {_id : 1, items : 1}}

最后,这个投影并不是真正需要的,但我将它包括在内以说明功能 - 如果您愿意,您可以选择不返回 _id 等。

于 2012-09-05T11:13:33.510 回答
-1

$elemMatch 和 MongoDB 通常都不会过滤数组中的数据。$elemMatch 可用于匹配文档,但不会影响要返回的数据。您只能使用过滤器参数(find() findOne() 调用的第二个参数)从文档中包含/排除字段,但您不能根据某些查询输入过滤结果。

于 2012-09-05T05:47:13.937 回答