2014-09-06 43 views
2

这里是我的示例文件:通过投影从嵌套的文件全部删除,但一个领域

{ 
    a: 42, 
    map: { 
    x: { ... }, 
    y: { ... }, 
    z: { ... } 
    } 
} 

我正在寻找一种方法来仅返回:

{ 
    a: 42, 
    map: { 
    y: { ... } 
    } 
} 

我只想说明地图内的字段保持为。类似的东西...

db.myCollection.find({}, 
    { 
    "map.y":1 
    } 
) 

... 也应该返回现场a没有明确指定它。

我知道我也可以删除不需要的映射条目:

db.myCollection.find({}, 
    { 
    "map.x":0, 
    "map.z":0 
    } 
) 

可是这样一来,我需要知道在我运行查询该地图键可用。

有没有一种很好的方法来处理这个问题?也许使用聚合框架?

谢谢:)

回答

2

这基本上是如何投影或字段选择MongoDB中以及许多其它数据库系统的工作原理。这里的概念基本上是“全部或全部”,因为如果你没有指定你想返回的所有字段,它们不会被返回,当然默认是返回你没有具体说明你想要的东西。

因此,对当前数据的正确形式只返回amap.y是:

db.myCollection.find({}, { "a": 1, "map.y": 1 }) 

或者当然你告诉它你不想要的东西:

db.myCollection.find({}, { "map.x": 0, "map.z": 0 }) 

但你不能“混合”包含和排除,唯一的例外是_id字段,您不希望在结果中使用该字段,可能会想到“覆盖索引”查询,但通常需要主键:

db.myCollection.find({}, { "_id": 0, "a": 1, "map.y": 1 }) 

至于聚合框架,它是相同的,特别和同样残酷的运营商,如$project$group。在这两种情况下,您都需要明确指定要返回的内容($ project也遵循通用投影规则),或者这些字段不在结果中。

事实上,一个常见的错误使我的人们与这些阶段中的一个“清除”字段,然后试图指的是后来被移除的字段。这是一个“管道”,就像Unix管道|一样,流向下一个阶段的唯一内容是你指定的内容:

唯一的“真实”情况,你可以排除除匹配字段外的所有内容而不指定其他字段是通过改变你的结构来实现“map”作为一个数组,然后使用从MongoDB 2.6及更高版本可用的流水线阶段。虽然有点做作:

db.test.insert({ 
    "a": 42, 
    "map": [ 
     { "type": "x", "content": {} }, 
     { "type": "y", "content": {} }, 
     { "type": "z", "content": {} } 
    ] 
}) 

而且在结构类似于该数据的聚合操作:

db.test.aggregate([ 
    { "$redact": { 
     "$cond": [ 
      { "$eq": [ 
       { "$ifNull": [ "$type", "y" ] }, 
       "y" 
      ]}, 
      "$$DESCEND", 
      "$$PRUNE" 
     ] 
    }} 
]) 

就这样,我们只要求元素与“型”匹配等于“Y”,但你由于$ redact正在递归处理,因此一般需要小心,这就是为什么$ifNull运算符人为地在测试字段不存在的级别创建匹配。

但通常情况下,投影是全部或没有。指定您想要返回的字段或者他们不会在那里。

+0

太糟糕了,因为数组不会映射到我的Java类。但我当然可以解决这个问题。 '...'现在我有第二个小问题了:当使用'type'和'content'的数组方法时,是否可以使用'elemMatch'运算符与投影相反?即(伪代码)'map:{$ elemMatch:{type:NOT“y”}}:0',所以它会从数组中删除所有内容,其中'type!=“y”'。 – 2014-09-06 05:02:29

+0

@BenjaminM正如我所解释的,没有其他方式可以让另一个领域(如“a”)出现,而没有特别说明你想要返回。 $ redact是从文档中“删除”元素的特殊情况,在这种情况下,“类型”字段不匹配。所以没有其他方式意味着没有其他办法。 – 2014-09-06 05:10:55

+0

谢谢,对于'!!!'这个伟大的解释,我将不得不考虑一下。我可以使用第二个集合作为'map',然后我可以很容易地使用标准投影。 – 2014-09-06 05:12:37