【问题标题】:Return a subset of array where a given field is present返回存在给定字段的数组子集
【发布时间】:2016-05-15 17:31:53
【问题描述】:

我想过滤 Categories 嵌入式数组以仅获取具有 parent 键的数组。

{
    "_id": ObjectId("5737283639533c000978ae71"),
    "name": "Swiss",
    "Categories": [
        {
            "name": "Management",
            "_id": ObjectId("5738982e39533c00070f6a53")
        },
        {
            "name": "Relations",
            "_id": ObjectId("5738984a39533c000978ae72"),
            "parent": ObjectId("5738982e39533c00070f6a53")
        },
        {
            "name": "Ambiance",
            "_id": ObjectId("57389bed39533c000b148164")
        }
    ]
}

我已尝试使用find,但没有成功。 经过一番研究,它似乎可以通过聚合命令完成,但我不喜欢它的工作方式,我宁愿只使用 find 命令。

另外,我问自己,就性能而言,将每个类别存储在一个新集合中不是更好吗?

编辑,我想得到这样的东西作为查找输出:

    [
        {
            "name": "Relations",
            "_id": ObjectId("5738984a39533c000978ae72"),
            "parent": ObjectId("5738982e39533c00070f6a53")
        }
    ]

【问题讨论】:

    标签: php mongodb mongodb-query aggregation-framework mongodb-php


    【解决方案1】:

    最佳方法是在 MongoDB 3.2 中使用聚合框架。您所需要的只是投影您的文档并使用$filter 运算符返回与您的条件匹配的“类别”数组的子集,但要做到这一点,您需要使用$ifNull 运算符为在所有那些缺少该字段的子文档中的“父”字段,然后在您的cond 表达式中使用$ne,该表达式确定给定元素应包含在子集中的哪个位置。

    db.collection.aggregate([
        { "$project" : { 
            "_id": 0, 
            "Categories": { 
                "$filter": { 
                    "input": "$Categories", 
                    "as": "catg", 
                    "cond": { 
                        "$ne": [
                            { "$ifNull": [ "$$catg.parent", false ] }, 
                            false
                        ]
                    }
                }
            }
        }}
    ])
    

    从 3.0 版本开始,您需要一种不同的方法。相反,您需要使用$map 运算符返回一个给定元素,如果它符合您的条件或false 然后使用$setDifference 运算符过滤掉返回数组中等于false 的所有元素。当然$setDifference 没问题,只要被过滤的数据是“唯一的”。

    db.collection.aggregate([
        { "$project" : { 
            "_id": 0, 
            "Categories": { 
                "$setDifference": [ 
                    { "$map": { 
                        "input": "$Categories", 
                        "as": "catg", 
                        "in": { 
                             "$cond": [ 
                                 { "$ne": [
                                     { "$ifNull": [ "$$catg.parent", false ] },
                                     false
                                 ]}, 
                                 "$$catg", 
                                 false
                            ]}
                        }
                    }, 
                    [ false ] 
                ]
            }
        }}
    ])
    

    PHP 中的翻译给出:

    db.collection.aggregate(
        array(
            array("$project" => array(
                "_id" => 0, 
                "Categories" => array( 
                    "$filter" => array(
                        "input" => "$Categories", 
                        "as" => "catg", 
                        "cond" => array(
                             "$ne" => array(
                                 array("$ifNull" => array("$$catg.parent", false), 
                             false
                        )
                    )
                  )  
              )
          ))
       )
    )
    

    还有这样的:

    db.collection.aggregate(
        array(
            array("$project" => array( 
                "_id" => 0, 
                "Categories" => array( 
                    "$setDifference" => array(
                        "$map" => array( 
                            "input" => "$Categories", 
                            "as" => "catg", 
                            "in" => array( 
                                "$cond" => array(
                                    "$ne" => array(
                                         array("$ifNull" => array( "$$catg.parent", false ) ),
                                         false
                                ), 
                                "$$catg", 
                                false
                            )
                        ),
                        array(false) 
                    )
                )
            ))
        )
    )
    

    【讨论】:

      【解决方案2】:

      作为根据上述描述的解决方案,请尝试执行以下查询

      db.mycoll.find({Categories:{$elemMatch:{parent:{$exists:true}}}},
      
      {Categories:{$elemMatch:{parent:{$exists:true}}}})
      

      以上示例使用$elemMatch 运算符过滤嵌入文档中的元素。

      【讨论】:

      • 是的,但我得到了整个文档,而不仅仅是我想要的部分。我将编辑我的问题以使其更清楚。
      • 你不能在这里使用带有$elemMatch的投影,因为它只会返回数组中的第一个匹配项。
      猜你喜欢
      • 2012-09-14
      • 2017-03-28
      • 2014-06-08
      • 1970-01-01
      • 1970-01-01
      • 2015-09-05
      • 1970-01-01
      • 2014-07-01
      • 1970-01-01
      相关资源
      最近更新 更多