我有这个问题:
我需要进行查询,获取外部数据(通过查找),“多对多”和“一对多”。
我的数据看起来是这样的:
转账集合:
{
"_id": 1,
"requests": [
{
"service": 1,
"foo": "foo1",
"bar": "bar1"
},
{
"service": 2,
"foo": "foo2",
"bar": "bar2"
}
]
}
因此,“服务”字段是另一个集合“服务”的外部 ID。
服务集合:
[{ _id: 1, name: 'Service 1" }, { _id: 2, name: 'Service 2' }]
问题是:如何在 Transfer 集合中按服务名称进行过滤?我知道 Mongoose 的填充,但这不允许通过外部数据进行过滤(另外,我的函数需要分页(我使用 Mongoose 分页插件),因此,我在执行后放弃过滤,因为这可以从少量数据中过滤宇宙)。
我认为最好的选择是使用聚合。 但是,如果我做到了......
db.transfers.aggregate([
{
$lookup: {
from: 'services',
localField: 'requests.service',
foreignField: '_id',
as: 'requests.service'
}
}
])
我得到了这个:
{
"_id" : 1,
"requests" : {
"service" : [
{
"_id" : 1,
"name" : "Service 1"
},
{
"_id" : 1,
"name" : "Service 2"
}
]
}
}
如何在不更改查询的情况下将服务数据放入主体对象中?
显然,聚合函数在“请求”(许多)上添加“展开”,但不在“服务”(一个)上添加“展开”
无论如何,我需要返回的数据:
{
"_id" : 1,
"requests": [
{
"service": {
"_id" : 1,
"name" : "Service 1"
},
"foo": "foo1",
"bar": "bar1"
},
{
"service": {
"_id" : 2,
"name" : "Service 2"
},
"foo": "foo2",
"bar": "bar2"
}
]
}
最佳答案
这是一个解决方案 - 现在不确定它是否是最漂亮的,但它肯定可以完成工作:
db.transfers.aggregate([{
$lookup: {
from: 'services',
localField: 'requests.service',
foreignField: '_id',
as: 'requests2'
}
}, {
$project: {
"requests": {
$map: {
"input": {
$zip: {
"inputs": [ "$requests", "$requests2" ]
}
},
"as": "this",
"in": {
$mergeObjects: [
{ $arrayElemAt: [ "$$this", 0 ] },
{ "service": { $arrayElemAt: [ "$$this", 1 ] } }
]
}
}
}
}
}])
第二个选项是这样做:
db.transfers.aggregate([{
$lookup: {
from: 'services',
localField: 'requests.service',
foreignField: '_id',
as: 'requests2'
}
}, {
$project: {
"requests": {
$map: {
"input": {
$range: [ 0, { $size: "$requests2" } ]
},
"as": "index",
"in": {
$mergeObjects: [
{ $arrayElemAt: [ "$requests", "$$index" ] },
{ "service": { $arrayElemAt: [ "$requests2", "$$index" ] } }
]
}
}
}
}
}])
我从未真正比较过两个版本的性能,但我怀疑第二个版本更快一点。
关于node.js - MongoDB 聚合查找和展开,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52562112/