MongoDB 聚合合并两个查找?
MongoDB Aggregate combine two lookups?
所以我的架构分为节点和链接。链接集合包含
之类的文档
{src: A, dst:B, value:int}
节点集合有
{name:A, ...other info}
我正在尝试为节点聚合信息,以仅使用一个聚合函数来查找发送值数据与接收值数据。
我的聚合函数看起来像
{
"$lookup":{
"from":"links",
"localField":"name",
"foreignField":"dst",
"as":"recv"
}
},
{
"$lookup":{
"from":"links",
"localField":"name",
"foreignField":"src",
"as":"sent"
}
},
然后我只使用 $project
来总结 sent/recv 数组的值,结果是
{name:A, sent_value:x, recv_value:y}
这工作正常,但我注意到如果我取消其中一个查找,运行时间会显着减少。我正在寻找一种可能将两个查找组合到管道的一个阶段的方法。
我可以很好地分别为 sent 和 recv 发出两个聚合,但我想看看是否可以只使用一个聚合。
谢谢
编辑:示例数据
Nodes: {name: "A"}, {name: "B"},{name: "C"}
Links: {src: "A", dst: "B",value:25}, {src: "A", dst: "C", value:3}, {src: "B",dst: "C", value:19}
我想从一个聚合中得到我上面描述的:
{name: "A", sent:28, recv: 0}, {name: "B", sent:19, recv:25}, {name: "C",sent:0,recv:22}
您可以做一个 $lookup
来一次获取所有 dst 和 src 数据。然后,使用$reduce
对数组进行条件求和。
db.nodes.aggregate([
{
"$lookup": {
"from": "links",
let: {
name: "$name"
},
pipeline: [
{
$match: {
$expr: {
$or: [
{
$eq: [
"$$name",
"$src"
]
},
{
$eq: [
"$$name",
"$dst"
]
}
]
}
}
}
],
"as": "linksLookup"
}
},
{
"$project": {
name: 1,
recv: {
"$reduce": {
"input": "$linksLookup",
"initialValue": 0,
"in": {
"$add": [
"$$value",
{
"$cond": {
"if": {
$eq: [
"$$this.dst",
"$name"
]
},
"then": "$$this.value",
"else": 0
}
}
]
}
}
},
sent: {
"$reduce": {
"input": "$linksLookup",
"initialValue": 0,
"in": {
"$add": [
"$$value",
{
"$cond": {
"if": {
$eq: [
"$$this.src",
"$name"
]
},
"then": "$$this.value",
"else": 0
}
}
]
}
}
}
}
}
])
这里是Mongo playground供大家参考。
所以我的架构分为节点和链接。链接集合包含
之类的文档{src: A, dst:B, value:int}
节点集合有
{name:A, ...other info}
我正在尝试为节点聚合信息,以仅使用一个聚合函数来查找发送值数据与接收值数据。
我的聚合函数看起来像
{
"$lookup":{
"from":"links",
"localField":"name",
"foreignField":"dst",
"as":"recv"
}
},
{
"$lookup":{
"from":"links",
"localField":"name",
"foreignField":"src",
"as":"sent"
}
},
然后我只使用 $project
来总结 sent/recv 数组的值,结果是
{name:A, sent_value:x, recv_value:y}
这工作正常,但我注意到如果我取消其中一个查找,运行时间会显着减少。我正在寻找一种可能将两个查找组合到管道的一个阶段的方法。 我可以很好地分别为 sent 和 recv 发出两个聚合,但我想看看是否可以只使用一个聚合。 谢谢
编辑:示例数据
Nodes: {name: "A"}, {name: "B"},{name: "C"}
Links: {src: "A", dst: "B",value:25}, {src: "A", dst: "C", value:3}, {src: "B",dst: "C", value:19}
我想从一个聚合中得到我上面描述的:
{name: "A", sent:28, recv: 0}, {name: "B", sent:19, recv:25}, {name: "C",sent:0,recv:22}
您可以做一个 $lookup
来一次获取所有 dst 和 src 数据。然后,使用$reduce
对数组进行条件求和。
db.nodes.aggregate([
{
"$lookup": {
"from": "links",
let: {
name: "$name"
},
pipeline: [
{
$match: {
$expr: {
$or: [
{
$eq: [
"$$name",
"$src"
]
},
{
$eq: [
"$$name",
"$dst"
]
}
]
}
}
}
],
"as": "linksLookup"
}
},
{
"$project": {
name: 1,
recv: {
"$reduce": {
"input": "$linksLookup",
"initialValue": 0,
"in": {
"$add": [
"$$value",
{
"$cond": {
"if": {
$eq: [
"$$this.dst",
"$name"
]
},
"then": "$$this.value",
"else": 0
}
}
]
}
}
},
sent: {
"$reduce": {
"input": "$linksLookup",
"initialValue": 0,
"in": {
"$add": [
"$$value",
{
"$cond": {
"if": {
$eq: [
"$$this.src",
"$name"
]
},
"then": "$$this.value",
"else": 0
}
}
]
}
}
}
}
}
])
这里是Mongo playground供大家参考。