在文档数组中查找包含字段的子文档

Posted

技术标签:

【中文标题】在文档数组中查找包含字段的子文档【英文标题】:Looking for sub-documents containing a field in a document's array 【发布时间】:2016-04-23 21:27:03 【问题描述】:

假设我有以下persons 集合:


  "_id": ObjectId("569d07a38e61973f6aded134"),
  "name": "john",
  "pets": [
    
      "name": "spot",
      "type": "dog",
      "special": "spot eye"
    ,
    
      "name": "bob",
      "type": "cat",
    
  ]
,

  "_id": ObjectId("569d07a38e61973f6aded135"),
  "name": "susie",
  "pets": [
    
      "name": "fred",
      "type": "cat",
    
  ]

我如何检索宠物中具有special 字段的人?我希望返回的 pets 数组仅包含带有 special 字段的宠物。

例如,上述集合的预期结果是:


  "_id": ObjectId("569d07a38e61973f6aded134"),
  "name": "john",
  "pets": [
    
      "name": "spot",
      "type": "dog",
      "special": "spot eye"
    
  ]

我希望在一个使用pymongo 的查询中实现这一点,尽管即使只是一个工作的 MongoDB 或猫鼬查询也会很可爱。

我尝试过:

db.persons.find(pets:special:$exists:true);

但它返回了 0 条记录,即使应该有一些。

【问题讨论】:

【参考方案1】:

如果数组包含嵌入文档,您可以使用dot notation查询嵌入文档中的特定字段。

如果没有点表示法,您正在查询数组文档以获得完整匹配。

尝试以下查询:

db.persons.find('pets.special':$exists:true);

【讨论】:

谢谢。这确实适用于mongo 终端,但由于某种原因,以下pymongo 查询返回完整数组,包括那些没有special 的数组:mperson.find( "pets.special": "$exists":"true" )。知道为什么吗? 你需要使用python布尔值True而不是字符串“true”:mperson.find( "pets.special": "$exists": True )【参考方案2】:

您可以使用 aggregation framework 来获得所需的结果。运行以下聚合管道:

db.persons.aggregate([
    
        "$match": 
            "pets.special":  "$exists": true 
        
    ,
    
        "$project": 
            "name": 1,             
            "pets": 
                "$setDifference": [
                    
                        "$map": 
                            "input": "$pets",
                            "as": "el",
                            "in": 
                                "$cond": [
                                     "$gt": [ "$$el.special", null ] ,

                                    "$$el", false 
                                ]
                            
                        
                    ,
                    [false]
                ]
            
        
    
])

样本输出


    "result" : [ 
        
            "_id" : ObjectId("569d07a38e61973f6aded134"),
            "name" : "john",
            "pets" : [ 
                
                    "name" : "spot",
                    "type" : "dog",
                    "special" : "spot eye"
                
            ]
        
    ],
    "ok" : 1

产生显着差异的运算符是 $setDifference$map 运算符。 $map 运算符本质上创建了一个新的数组字段,该字段保存值作为数组每个元素的子表达式中的评估逻辑的结果。 $setDifference 运算符然后返回一个集合,其中包含出现在第一个集合中但不在第二个集合中的元素;即相对于第一组执行第二组的相对补充。在这种情况下,它将返回最终的 pets 数组,其中包含与父文档无关的元素,基于 special 属性的存在,基于条件运算符 $cond 评估比较运算符返回的表达式 $gt

【讨论】:

以上是关于在文档数组中查找包含字段的子文档的主要内容,如果未能解决你的问题,请参考以下文章

查找其数组字段包含给定数组的至少 n 个元素的文档

Mongodb检查数组的子文档中是否存在字段

从数组中查找并返回第一个匹配的子文档(Meteor / Mongo)

查找 Mongodb 文档,如果它包含 mongoose 中的数组中的元素

仅返回嵌套数组中匹配的子文档元素

如何匹配 MongoDB 中的子文档数组?