栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

$ lookup之后的聚合过滤器

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

$ lookup之后的聚合过滤器

这里的问题实际上是关于一些不同的东西,根本不需要

$lookup
。但是,对于仅从“$lookup之后过滤”标题到达此处的任何人,这些都是适合您的技术:

MongoDB 3.6-子管道

db.test.aggregate([    { "$match": { "id": 100 } },    { "$lookup": {      "from": "test",      "let": { "id": "$id" },      "pipeline": [        { "$match": {          "value": "1",          "$expr": { "$in": [ "$$id", "$contain" ] }        }}      ],      "as": "childs"    }}])

较早-$ lookup + $ unwind + $ match合并

db.test.aggregate([    { "$match": { "id": 100 } },    { "$lookup": {        "from": "test",        "localField": "id",        "foreignField": "contain",        "as": "childs"    }},    { "$unwind": "$childs" },    { "$match": { "childs.value": "1" } },    { "$group": {        "_id": "$_id",        "id": { "$first": "$id" },        "value": { "$first": "$value" },        "contain": { "$first": "$contain" },        "childs": { "$push": "$childs" }     }}])

如果您质疑为什么不

$unwind
使用
$filter
该数组,请阅读[Aggregate$lookup匹配管道中文档的总大小超出了所有文档的最大文档大小,以了解为什么这是通常必需的并且是最佳方法。

对于MongoDB 3.6及更高版本,通常是更具表现力的“子管道”,它是您想要在所有内容完全返回数组之前“过滤”外部集合的结果的工具。

回到答案,尽管实际上描述了为什么所提问题根本不需要“不参加”。


原版的

$lookup
像这样使用并不是在这里执行所需操作的最“有效”方法。但是稍后会详细介绍。

作为一个基本概念,只需

$filter
在结果数组上使用:

db.test.aggregate([     { "$match": { "id": 100 } },     { "$lookup": {        "from": "test",        "localField": "id",        "foreignField": "contain",        "as": "childs"    }},    { "$project": {        "id": 1,        "value": 1,        "contain": 1,        "childs": {"$filter": {    "input": "$childs",    "as": "child",    "cond": { "$eq": [ "$$child.value", "1" ] }}        }    }}]);

$redact
改为使用:

db.test.aggregate([     { "$match": { "id": 100 } },     { "$lookup": {        "from": "test",        "localField": "id",        "foreignField": "contain",        "as": "childs"    }},    { "$redact": {        "$cond": {"if": {   "$or": [     { "$eq": [ "$value", "0" ] },     { "$eq": [ "$value", "1" ] }   ]},"then": "$$DESCEND","else": "$$PRUNE"        }    }}]);

两者都得到相同的结果:

{    "_id":ObjectId("570557d4094a4514fc1291d6"),  "id":100,  "value":"0",  "contain":[ ],  "childs":[ {        "_id":ObjectId("570557d4094a4514fc1291d7"),      "id":110,      "value":"1",      "contain":[ 100 ]    },    {        "_id":ObjectId("570557d4094a4514fc1291d8"),      "id":120,      "value":"1",      "contain":[ 100 ]    }  ]}

最重要的是,

$lookup
它本身不能“还”查询以仅选择某些数据。因此,所有“过滤”都需要在
$lookup

但是,实际上对于这种类型的“自我连接”,您最好根本不使用它

$lookup
,并且完全避免额外读取和“哈希合并”的开销。只需获取相关项目,即可
$group

db.test.aggregate([  { "$match": {     "$or": [      { "id": 100 },      { "contain.0": 100, "value": "1" }    ]  }},  { "$group": {    "_id": {      "$cond": {        "if": { "$eq": [ "$value", "0" ] },        "then": "$id",        "else": { "$arrayElemAt": [ "$contain", 0 ] }      }    },    "value": { "$first": { "$literal": "0"} },    "childs": {      "$push": {        "$cond": {          "if": { "$ne": [ "$value", "0" ] },          "then": "$$ROOT",          "else": null        }      }    }  }},  { "$project": {    "value": 1,    "childs": {      "$filter": {        "input": "$childs",        "as": "child",        "cond": { "$ne": [ "$$child", null ] }      }    }  }}])

这只是有所不同,因为我故意删除了多余的字段。如果您确实要添加它们,请自己添加:

{  "_id" : 100,  "value" : "0",  "childs" : [    {      "_id" : ObjectId("570557d4094a4514fc1291d7"),      "id" : 110,      "value" : "1",      "contain" : [ 100 ]    },    {      "_id" : ObjectId("570557d4094a4514fc1291d8"),      "id" : 120,      "value" : "1",      "contain" : [ 100 ]    }  ]}

因此,这里唯一真正的问题是“过滤”

null
来自数组的任何结果,该数组是在当前文档正在
parent
处理到时创建的
$push


您在这里似乎还缺少的是,您要查找的结果根本不需要聚合或“子查询”。您已经结束或可能在其他地方找到的结构是“设计的”,因此您可以在单个查询请求中获得一个“节点”及其所有“子代”。

这意味着只有“ query”才是真正需要的,而数据收集(由于没有真正“减少”任何内容而已发生的一切)只是迭代游标结果的功能:

var result = {};db.test.find({  "$or": [    { "id": 100 },    { "contain.0": 100, "value": "1" }  ]}).sort({ "contain.0": 1 }).forEach(function(doc) {  if ( doc.id == 100 ) {    result = doc;    result.childs = []  } else {    result.childs.push(doc)  }})printjson(result);

这做的完全一样:

{  "_id" : ObjectId("570557d4094a4514fc1291d6"),  "id" : 100,  "value" : "0",  "contain" : [ ],  "childs" : [    {      "_id" : ObjectId("570557d4094a4514fc1291d7"),      "id" : 110,      "value" : "1",      "contain" : [   100      ]    },    {      "_id" : ObjectId("570557d4094a4514fc1291d8"),      "id" : 120,      "value" : "1",      "contain" : [   100      ]    }  ]}

并证明您在这里真正需要做的就是发出“单个”查询以选择父项和子项。返回的数据是相同的,并且您在服务器或客户端上所做的所有工作都在“按摩”为另一种收集的格式。

这是在这种情况下您可以“思考”如何在“关系”数据库中进行操作的情况之一,而没有意识到由于数据的存储方式已“改变”,因此您不再需要使用同样的方法。

这正是文档示例 “带有子引用的模型树结构”结构中 的要点,它使在一个查询中选择父项和子项变得容易。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/430305.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号