Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mongodb 从$lookup和整个文档中获取数组中元素的筛选计数_Mongodb_Mongodb Query_Aggregation Framework - Fatal编程技术网

Mongodb 从$lookup和整个文档中获取数组中元素的筛选计数

Mongodb 从$lookup和整个文档中获取数组中元素的筛选计数,mongodb,mongodb-query,aggregation-framework,Mongodb,Mongodb Query,Aggregation Framework,我在MongoDB中有这个查询: db.emailGroup.aggregate([ { "$lookup": { "from": "link", "localField": "_id", "foreignField": "emailGroupId", "as": "link" }, }, { "$unwind"

我在MongoDB中有这个查询:

db.emailGroup.aggregate([
    {
        "$lookup": 
        {
            "from": "link",
            "localField": "_id",
            "foreignField": "emailGroupId",
            "as": "link"
        },
    },
    {
        "$unwind": "$link"
    },
    {
        "$match": {
             'link.originalLink': ""
        }
    },
    {
        "$group" : {
            _id: '$_id',
            link: {
                $push: '$link'
            }
        }
    },
    {
        "$project": { 
            "size": { 
                "$sum": { 
                    "$map": { 
                        "input": "$link", 
                        "as": "l", 
                        "in": { 
                            "$size": {
                                "$ifNull": [
                                    "$$l.linkHistory", []
                                ]
                            }
                        } 
                    } 
                } 
            }
        }
    }
])
EmailGroup具有partId字段。我使用$lookup来“加入”其他集合中的总和字段。我需要按partId字段分组,并为partId组求和自定义字段“大小”。这可能吗?额外问题:如何将emailGroup字段添加到查询结果

样本文件:

电子邮件组:

{
    "_id" : ObjectId("594a6c47f51e075db713ccb6"),
    "partId" : "f56c7c71eb14a20e6129a667872f9c4f",
}
链接:

{
    "_id" : ObjectId("594b96d6f51e075db67c44c9"),
    "originalLink" : "",
    "emailGroupId" : ObjectId("594a6c47f51e075db713ccb6"),
    "linkHistory" : [ 
        {
            "_id" : ObjectId("594b96f5f51e075db713ccdf"),
        }, 
        {
            "_id" : ObjectId("594b971bf51e075db67c44ca"),
        }
    ]
}
用于查找的注释-外部计数 比最初的回答要好一点的是,实际上使用了MongoDB3.6中更新的形式。这实际上可以在“子管道”表达式中进行“计数”,而不是返回“数组”进行后续过滤和计数,甚至使用

不是原始问题所要求的,而是以下答案的一部分,现在是最理想的形式,因为结果当然会减少到“匹配计数”,而不是“所有匹配的文档”


起初的 正确的方法是将
“linkCount”
添加到stage中,并在父文档的任何附加字段上添加一个,以获得“单数”表单,就像在数组上处理“之前”的状态一样,该状态是由以下原因造成的:

所有细节

db.emailGroup.aggregate([
  { "$lookup": {
    "from": "link",
    "localField": "_id",
    "foreignField": "emailGroupId",
    "as": "link"    
  }},
  { "$unwind": "$link" },
  { "$match": { "link.originalLink": "" } },
  { "$group": {
    "_id": "$_id",
    "partId": { "$first": "$partId" },
    "link": { "$push": "$link" },
    "linkCount": {
      "$sum": {
        "$size": {
          "$ifNull": [ "$link.linkHistory", [] ]
        } 
      }   
    }
  }}
])
db.emailGroup.aggregate([
  { "$lookup": {
    "from": "link",
    "localField": "_id",
    "foreignField": "emailGroupId",
    "as": "link"    
  }},
  { "$addFields": {
    "link": {
      "$filter": {
        "input": "$link",
        "as": "l",
        "cond": { "$eq": [ "$$l.originalLink", "" ] }    
      }
    },
    "linkCount": {
      "$sum": {
        "$map": {
          "input": {
            "$filter": {
              "input": "$link",
              "as": "l",
              "cond": { "$eq": [ "$$l.originalLink", "" ] }
            }
          },
          "as": "l",
          "in": { "$size": { "$ifNull": [ "$$l.linkHistory", [] ] } }
        }     
      }
    }    
  }}
])
产生:

{
    "_id" : ObjectId("594a6c47f51e075db713ccb6"),
    "partId" : "f56c7c71eb14a20e6129a667872f9c4f",
    "link" : [ 
        {
            "_id" : ObjectId("594b96d6f51e075db67c44c9"),
            "originalLink" : "",
            "emailGroupId" : ObjectId("594a6c47f51e075db713ccb6"),
            "linkHistory" : [ 
                {
                    "_id" : ObjectId("594b96f5f51e075db713ccdf")
                }, 
                {
                    "_id" : ObjectId("594b971bf51e075db67c44ca")
                }
            ]
        }
    ],
    "linkCount" : 2
}
按党派分组

db.emailGroup.aggregate([
  { "$lookup": {
    "from": "link",
    "localField": "_id",
    "foreignField": "emailGroupId",
    "as": "link"    
  }},
  { "$unwind": "$link" },
  { "$match": { "link.originalLink": "" } },
  { "$group": {
    "_id": "$partId",
    "linkCount": {
      "$sum": {
        "$size": {
          "$ifNull": [ "$link.linkHistory", [] ]
        } 
      }   
    }
  }}
])
db.emailGroup.aggregate([
  { "$lookup": {
    "from": "link",
    "localField": "_id",
    "foreignField": "emailGroupId",
    "as": "link"    
  }},
  { "$addFields": {
    "link": {
      "$filter": {
        "input": "$link",
        "as": "l",
        "cond": { "$eq": [ "$$l.originalLink", "" ] }    
      }
    },
    "linkCount": {
      "$sum": {
        "$map": {
          "input": {
            "$filter": {
              "input": "$link",
              "as": "l",
              "cond": { "$eq": [ "$$l.originalLink", "" ] }
            }
          },
          "as": "l",
          "in": { "$size": { "$ifNull": [ "$$l.linkHistory", [] ] } }
        }     
      }
    }    
  }},
  { "$unwind": "$link" },
  { "$group": {
    "_id": "$partId",
    "linkCount": { "$sum": "$linkCount" } 
  }}
])
产生

{
    "_id" : "f56c7c71eb14a20e6129a667872f9c4f",
    "linkCount" : 2
}
使用a和a这样做的原因是MongoDB在按该顺序发布时实际处理管道的方式。这就是操作的
“explain”
输出所演示的情况:

    {
        "$lookup" : {
            "from" : "link",
            "as" : "link",
            "localField" : "_id",
            "foreignField" : "emailGroupId",
            "unwinding" : {
                "preserveNullAndEmptyArrays" : false
            },
            "matching" : {
                "originalLink" : {
                    "$eq" : ""
                }
            }
        }
    }, 
    {
        "$group" : {
我将在输出中留下部分,以证明其他两个管道阶段“消失”。这是因为它们已“卷起”到管道阶段,如图所示。事实上,MongoDB就是这样处理的:将的结果“连接”到父文档的数组中,可能会超过BSON限制

您可以这样交替编写操作:

所有细节

db.emailGroup.aggregate([
  { "$lookup": {
    "from": "link",
    "localField": "_id",
    "foreignField": "emailGroupId",
    "as": "link"    
  }},
  { "$unwind": "$link" },
  { "$match": { "link.originalLink": "" } },
  { "$group": {
    "_id": "$_id",
    "partId": { "$first": "$partId" },
    "link": { "$push": "$link" },
    "linkCount": {
      "$sum": {
        "$size": {
          "$ifNull": [ "$link.linkHistory", [] ]
        } 
      }   
    }
  }}
])
db.emailGroup.aggregate([
  { "$lookup": {
    "from": "link",
    "localField": "_id",
    "foreignField": "emailGroupId",
    "as": "link"    
  }},
  { "$addFields": {
    "link": {
      "$filter": {
        "input": "$link",
        "as": "l",
        "cond": { "$eq": [ "$$l.originalLink", "" ] }    
      }
    },
    "linkCount": {
      "$sum": {
        "$map": {
          "input": {
            "$filter": {
              "input": "$link",
              "as": "l",
              "cond": { "$eq": [ "$$l.originalLink", "" ] }
            }
          },
          "as": "l",
          "in": { "$size": { "$ifNull": [ "$$l.linkHistory", [] ] } }
        }     
      }
    }    
  }}
])
按党派分组

db.emailGroup.aggregate([
  { "$lookup": {
    "from": "link",
    "localField": "_id",
    "foreignField": "emailGroupId",
    "as": "link"    
  }},
  { "$unwind": "$link" },
  { "$match": { "link.originalLink": "" } },
  { "$group": {
    "_id": "$partId",
    "linkCount": {
      "$sum": {
        "$size": {
          "$ifNull": [ "$link.linkHistory", [] ]
        } 
      }   
    }
  }}
])
db.emailGroup.aggregate([
  { "$lookup": {
    "from": "link",
    "localField": "_id",
    "foreignField": "emailGroupId",
    "as": "link"    
  }},
  { "$addFields": {
    "link": {
      "$filter": {
        "input": "$link",
        "as": "l",
        "cond": { "$eq": [ "$$l.originalLink", "" ] }    
      }
    },
    "linkCount": {
      "$sum": {
        "$map": {
          "input": {
            "$filter": {
              "input": "$link",
              "as": "l",
              "cond": { "$eq": [ "$$l.originalLink", "" ] }
            }
          },
          "as": "l",
          "in": { "$size": { "$ifNull": [ "$$l.linkHistory", [] ] } }
        }     
      }
    }    
  }},
  { "$unwind": "$link" },
  { "$group": {
    "_id": "$partId",
    "linkCount": { "$sum": "$linkCount" } 
  }}
])
具有相同的输出,但与第一个查询“不同”,即在“之后应用here,将的所有结果返回到父文档的新数组中

因此在性能方面,第一种方法实际上更有效,而且可以在“过滤前”移植到可能的大型结果集,否则将突破16MB BSON限制

注意:如果没有可用字段(随MongoDB 3.4一起添加),请使用并指定要返回的“所有”字段


对于那些感兴趣的人来说,在未来的MongoDB版本(大概是3.6及更高版本)中,您可以使用新的
$mergeObjects
管道操作符来代替a。其优点是作为一个“块”,我们可以通过将
“filtered”
内容声明为变量,这意味着您不需要“两次”写入相同的内容:

尽管如此,执行此类“过滤”操作的最佳方法是此时使用then模式“仍然”,直到您可以直接向提供查询参数为止

注意:这里我所说的“直接”并不是指MongoDB 3.6版本中的“非相关”形式,因为这确实会为父集合中的每个文档发出另一个“管道”执行。因此,该功能仍然不能取代目前仅检索匹配项的“最佳有效”方法


您只需在
$sum
末尾添加
$group
,即可从
$project
阶段计算
大小。您需要更新当前的
$group
$project
以包含
partId
$first
运算符(以及您希望保留在输出中的其他字段),以便在最后一个组中使用。请注意,您可以重构代码以删除
$unwind
+
$match
+
+
$group
阶段,并将其替换为
$map
内部的
$filter
并将
$project
阶段更改为
$addFields
,保留现有字段而不显式包含它们。@Veeram
$unwind+$match
不等于“
$filter
,事实上,服务器的处理方式完全不同。最大的区别在于“服务器”实际上将
$unwind
$match
卷到
$lookup
本身。这就是MongoDB处理可能超过BSON限制的结果的方式。相比之下,添加
$filter
仅在生成整个阵列之后应用。因此,
$unwind+$match+$group
实际上是更好的方法。不幸的是,目前无法简单地使用服务器此时应用的相同语法编写
$lookup
。Thx获取答案。有很多新的信息,但我没有一组一组地了解。当我使用{“$group”:{“$id”:“$\id”,“partId”:{“$first”:“$partId”},“link”:{“$push”:“$link”},“linkCount”:{“$sum”:{“$size”:{“$ifNull”:[“$link.linkHistory”,[]}}}}返回许多文档供选择partId。我需要一个具有相同partId的所有文档的sum linkHistory文档。在sql中,我可以实现子查询并对它们进行分组。这在mongoDB中可能吗?我是MongoDB的新手,你到底在问什么?您只需要
partId
和上面生成的“linkCount”的“sum”就可以了?你在问题中提到了“partId”,但它给人的印象是“事后思考”,而不是真正的问题。好吧,也许我无法解释这一点。我给你举个例子。A这一刻我有了那个结果:@nie就这样往上看。补充。