为了账号安全,请及时绑定邮箱和手机立即绑定

仅检索MongoDB集合中对象数组中的查询元素

/ 猿问

仅检索MongoDB集合中对象数组中的查询元素

幕布斯6054654 2019-05-21 13:56:35

仅检索MongoDB集合中对象数组中的查询元素

假设我的收藏中有以下文件:


{  

   "_id":ObjectId("562e7c594c12942f08fe4192"),

   "shapes":[  

      {  

         "shape":"square",

         "color":"blue"

      },

      {  

         "shape":"circle",

         "color":"red"

      }

   ]

},

{  

   "_id":ObjectId("562e7c594c12942f08fe4193"),

   "shapes":[  

      {  

         "shape":"square",

         "color":"black"

      },

      {  

         "shape":"circle",

         "color":"green"

      }

   ]

}

查询:


db.test.find({"shapes.color": "red"}, {"shapes.color": 1})

要么


db.test.find({shapes: {"$elemMatch": {color: "red"}}}, {"shapes.color": 1})

返回匹配的文档(文档1),但始终包含所有数组项shapes:


{ "shapes": 

  [

    {"shape": "square", "color": "blue"},

    {"shape": "circle", "color": "red"}

  ] 

}

但是,我想仅使用包含以下内容的数组来获取文档(文档1)color=red:


{ "shapes": 

  [

    {"shape": "circle", "color": "red"}

  ] 

}

我怎样才能做到这一点?


查看完整描述

4 回答

?
一只斗牛犬

MongoDB 2.2的新$elemMatch投影操作符提供了另一种方法来更改返回的文档以仅包含第一个匹配的shapes元素:

db.test.find(
    {"shapes.color": "red"}, 
    {_id: 0, shapes: {$elemMatch: {color: "red"}}});

返回:

{"shapes" : [{"shape": "circle", "color": "red"}]}

在2.2中,您也可以使用$ projection operator,其中$投影对象字段名称表示字段中查询的第一个匹配数组元素的索引。以下返回与上面相同的结果:

db.test.find({"shapes.color": "red"}, {_id: 0, 'shapes.$': 1});

MongoDB 3.2更新

从3.2版本开始,您可以使用新的$filter聚合运算符在投影期间过滤数组,这样可以包含所有匹配,而不仅仅是第一个匹配。

db.test.aggregate([
    // Get just the docs that contain a shapes element where color is 'red'
    {$match: {'shapes.color': 'red'}},
    {$project: {
        shapes: {$filter: {
            input: '$shapes',
            as: 'shape',
            cond: {$eq: ['$$shape.color', 'red']}
        }},
        _id: 0
    }}])

结果:

[ 
    {
        "shapes" : [ 
            {
                "shape" : "circle",
                "color" : "red"
            }
        ]
    }]


查看完整回答
反对 回复 2019-05-21
?
交互式爱情

MongoDB 2.2+中的新聚合框架提供了Map / Reduce的替代方案。该$unwind操作可用于分离的shapes阵列到的文件流可以匹配:

db.test.aggregate(
  // Start with a $match pipeline which can take advantage of an index and limit documents processed
  { $match : {
     "shapes.color": "red"
  }},
  { $unwind : "$shapes" },
  { $match : {
     "shapes.color": "red"
  }})

结果是:

{
    "result" : [
        {
            "_id" : ObjectId("504425059b7c9fa7ec92beec"),
            "shapes" : {
                "shape" : "circle",
                "color" : "red"
            }
        }
    ],
    "ok" : 1}


查看完整回答
反对 回复 2019-05-21
?
冉冉说

字段选择器参数仅限于完整属性。它不能用于选择数组的一部分,只能用于整个数组。我尝试使用$ position运算符,但这不起作用。

最简单的方法是只过滤客户端中的形状。

如果您确实需要直接从MongoDB输出正确的输出,可以使用map-reduce来过滤形状。

function map() {
  filteredShapes = [];

  this.shapes.forEach(function (s) {
    if (s.color === "red") {
      filteredShapes.push(s);
    }
  });

  emit(this._id, { shapes: filteredShapes });}function reduce(key, values) {
  return values[0];}res = db.test.mapReduce(map, reduce, { query: { "shapes.color": "red" } })db[res.result].find()


查看完整回答
反对 回复 2019-05-21
?
白板的微信

另一种有趣的方法是使用$ redact,这是MongoDB 2.6的新聚合功能之一。如果您使用的是2.6,则不需要$ unwind,如果您有大型数组,可能会导致性能问题。

db.test.aggregate([
    { $match: { 
         shapes: { $elemMatch: {color: "red"} } 
    }},
    { $redact : {
         $cond: {
             if: { $or : [{ $eq: ["$color","red"] }, { $not : "$color" }]},
             then: "$$DESCEND",
             else: "$$PRUNE"
         }
    }}]);

$redact “根据文件本身存储的信息限制文件的内容”。所以它只会在文档内部运行。它基本上扫描你的文档顶部到底部,并检查它是否与你的if条件匹配$cond,如果有匹配,它将保留content($$DESCEND)或remove($$PRUNE)。

在上面的示例中,首先$match返回整个shapes数组,$ redact将其删除到预期结果。

请注意,这{$not:"$color"}是必要的,因为它也将扫描顶层文档,如果在顶层$redact找不到color字段,则返回false可能会删除我们不想要的整个文档。


查看完整回答
反对 回复 2019-05-21

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信