【问题标题】:Filter result after $graphLookup pipeline stage$graphLookup 管道阶段后的过滤结果
【发布时间】:2017-01-17 06:45:16
【问题描述】:

我有字段相同的父记录和子记录。但是,某些字段仅设置在父级。

设置为空字符串 ("") 的父字段表示该记录是父记录。其他记录具有指向父记录的值集,因此这些记录可以被视为子记录。

现在考虑以下记录:

{"_id": 1, parent: "", "pValue": ["a", "b", "c"], fieldA: 2},
{"_id": 2, parent: 1, "pValue": [], fieldA: 2},
{"_id": 3, parent: 1, "pValue": [], fieldA: 2},
{"_id": 4, parent: "", "pValue": ["d"], fieldA: 9},
{"_id": 5, parent: 4, "pValue": [], fieldA:2},
{"_id": 6, parent: 4,"pValue": [], fieldA: 9}

上述记录包含两个父母,每个父母都有 2 个关联的子记录。我尝试执行的查询涉及匹配两个给定的参数。首先是 pValue 上的一个值。一旦我在他们的数组中获得具有特定 pValue 的所有父母。然后,我想将该父项及其关联的所有子记录与 fieldA 值匹配。

所以如果给定 pValue="d" 和 fieldA=9 我希望光标内有以下记录:

{"_id": 4, parent: "", "pValue": ["d"], fieldA: 9}
{"_id": 6, parent: 4, "pValue": [],fieldA: 9}

注意事项:

  1. 每个父级可以有许多与其关联的子级。
  2. 父级可以为子级设置不同的 fieldA 值,并且查询应该只返回子级而不是父级

我的尝试:

 cursor=self.pCollection.aggregate([
      { "$match": {"pValue":{"$in":[pCheck]}},
      {   "$graphLookup" : {
          "from": "pCollection",
          "startWith": "$_id",
          "connectFromField": "_id",
          "connectToField": "parent",
          "as" : "children"
          }
      }])

然后,我被困在所有与父级关联的子级数组中,却不知道如何对它们进行向上包装。

【问题讨论】:

  • 你能显示预期的结果吗?
  • 嗨 Styvane,说我想在 fieldA=2 上匹配结果将只是记录 {"_id":3,"fieldA":2,"fieldB":8,"pValue": ["a","b"],parent:1} 但是它需要首先通过graphLookup
  • 此外,如果父记录的 fieldA 值也为 2,它将返回两条记录,即父母和孩子
  • 好的,请编辑您的问题以添加具有预期结果的示例文档。

标签: python mongodb aggregation-framework


【解决方案1】:

您需要使用$match 选择与您的查询条件匹配的文档,并在添加$addFields 阶段过滤“children”数组。

$filtering 之后,您可以使用arrayElemAt 将项目分配到一个字段。

{ "$match": { "fieldA": 9, "children.fieldA": 9 } },
{ "$addFields": { 
    "children": {
        "$arrayElemAt": [
            { "$filter": { 
                "input": "$children",
                "as": "child",
                "cond": { "$eq": [ "$$child.fieldA", 9 ] }
            }},
            0
         ]
    }
}}

您的查询将产生如下内容:

{
    "_id" : 4,
    "parent" : "",
    "pValue" : [ "d" ],
    "fieldA" : 9,
    "children" : { "_id" : 6, "parent" : 4, "pValue" : [ ], "fieldA" : 9 }
}

不过,只要有一点信心,你就能得到你所期望的结果。

db.collection.aggregate([
    { "$graphLookup": {
        "from": "collection",
        "startWith": "$_id", 
        "connectFromField": "_id",           
        "connectToField": "parent",     
        "as" : "children"
    }}, 
    { "$match": { "fieldA": 9, "children.fieldA": 9 } }, 
    { "$addFields": { 
        "children": { 
            "$arrayElemAt": [ 
                { "$filter": { 
                    "input": "$children", 
                    "as": "child", 
                    "cond": { "$eq": [ "$$child.fieldA", 9 ] } 
                }}, 
                0 
            ] 
        }
    }}, 
    { "$project": { 
        "children": [
            "$children", 
            { 
                "_id": "$_id", 
                "parent": "$parent", 
                "pValue": "$pValue", 
                "fieldA": "$fieldA" 
            }
        ]
    }}, 
    { "$unwind": "$children" }, 
    { "$replaceRoot": { "newRoot": "$children" } }
])

产生这样的东西:

{ "_id" : 6, "parent" : 4, "pValue" : [ ], "fieldA" : 9 }
{ "_id" : 4, "parent" : "", "pValue" : [ "d" ], "fieldA" : 9 }

坦率地说,我认为这不是您应该在应用程序中做的事情。第一个选项是您可以并且应该接受的。

如果你真的需要这个,我建议你create a view 并在你的应用程序中查询视图。

【讨论】:

  • @tyvane:我正在尝试您的脚本,但无法使用我的数据库:db.getCollection('categories').aggregate( [ { $graphLookup: { from: "categories", startWith: "$ CategoryParent", connectFromField: "CategoryParent", connectToField: "_id", as: "testHierarchy" } }, { "$match": { "_id": ObjectId('5b4daacce3d25a27c81417f4') } } ]);因为字段:'CategoryParent' 是字符串,而字段:'_id' 是 ObjectId。我不知道如何将 ObjectId 类型的字段“_id”转换为字符串
【解决方案2】:

通过反转查询并首先在 fieldA 上进行匹配,然后从父级执行 graphyLookup--> _id(因此将父级映射到子级),然后我能够将子级关联到其父级的 fieldA。

这是我最终得到的查询:

     cursor=self.collection.aggregate([
          { "$match": {"fieldA":9}},
          { "$graphLookup" : {
            "from": "collection",
            "startWith": "$parent",
            "connectFromField": "parent",
            "connectToField": "_id",
            "as" : "parents"
            }
          },
          { "$project" : {
             "pValue": { "$cond":[ {"$ne":["$pValue",[]]},"$pValue",  
                                     {"$let":{"vars": {"obj": {"$arrayElemAt": ["$parents", 0]}},
                                                               "in": "$$obj.pValue"}}]}
             }
          },
          { "$match": {"pValue":{"$in":["d"]}}}
        ])

【讨论】:

  • 由于您使用的是 MongoDB 3.4,因此请使用 $switch 而不是 $cond,就像我在回答您的其他问题时所做的那样,您的意图很明确。
  • 很酷,感谢 Styvane,我会改成那个。非常感谢您的帮助
  • 我怎样才能在字符串中 connectFromFeild 与 ObjectId 中的 connectToField?这是我的代码 db.getCollection('categories').aggregate( [ { $graphLookup: { from: "categories", startWith: "$CategoryParent", connectFromField: "CategoryParent", connectToField: "_id", as: "testHierarchy " } }, { "$match": { "_id": ObjectId('5b4daacce3d25a27c81417f4') } } ]); connectFromField: "CategoryParent" => stringconnectToField: "_id" => ObjectId
猜你喜欢
  • 2017-05-24
  • 1970-01-01
  • 1970-01-01
  • 2020-08-12
  • 1970-01-01
  • 2019-04-10
  • 1970-01-01
  • 2020-01-27
  • 1970-01-01
相关资源
最近更新 更多