MongoDB - FindOne并过滤嵌套数组

时间:2015-03-05 12:01:03

标签: mongodb

我正在从SQL迁移到NoSQL,我正在尝试学习基础知识。但到目前为止,我一直在努力争取一个“选择陈述”

让我说我有这种收藏

文件1

{
  "_id" : "id1",
  "name" : "aa",
  "array"  : [
       {
          "nested_id"  : "n323123",
          "nesteddata" : "lorem",
          "active"     : 1
       },
       {
          "nested_id"  : "n353123",
          "nesteddata" : "lorem",
          "active"     : 0
       },
       {
          "nested_id"  : "n323123",
          "nesteddata" : "lorem",
          "active"     : 1
       }   
   ] 
}

文件2

{
      "_id" : "id2",
      "name" : "bb",
      "array"  : [
           {
              "nested_id"  : "n325123",
              "nesteddata" : "lorem",
              "active"     : 1
           },
           {
              "nested_id"  : "n355123",
              "nesteddata" : "lorem",
              "active"     : 1
           },
           {
              "nested_id"  : "n323123",
              "nesteddata" : "lorem",
              "active"     : 0
           }   
       ] 
 }

然后,我想选择一个,只有嵌套数据。 尝试过以下声明但没有成功。

db.testing.findOne(  {_id: "id1", "array.active" : 1} )

但我仍然在没有过滤器的情况下获得所有数据

1 个答案:

答案 0 :(得分:5)

首先,当你只想获得文档的一部分时,你需要使用find的双对象形式:

db.testing.findOne(  
    { _id: "id1", "array.active" : 1 },
    { array: 1 }
);

第二个对象告诉您要返回文档的哪些字段。但是,即使只有一个匹配的条目,此查询也将返回整个数组。但是你只想要一个特定的数组条目。所以你必须在第二个对象中使用positional-operator $。 “$”是数组条目的占位符,它与第一个对象匹配。

db.testing.findOne(  
    { _id: "id1", "array.active" : 1 },
    { "array.$": 1 }
);

对于您的用例,仍然存在可能会或可能不会出现问题的限制:$ -operator仅返回每个文档的每个数组的第一个条目。您正在使用findOne所以我假设您的目的是只获得一个数组条目。但这种限制可能会在将来咬你。

如果您想获得所有数组条目,则必须使用aggregation pipeline并执行3个步骤。

  1. 使用$match
  2. 过滤您需要结果的文档
  3. 使用$unwind
  4. 将数组展开为单个文档的流
  5. 通过适用于另一个$match
  6. 的数组属性的条件再次过滤生成的文档流
  7. (可选)仅使用$project
  8. 将文档缩减为您想要的字段

    此管道如下所示:

    db.testing.aggegate([
         { $match: { _id: "id1" } },
         { $unwind: { array: 1 } },
         { $match: { "array.active": 1 } },
         { $project: { _id: 0, array: 1 } 
     ]);