【问题标题】:MongoDB Aggregate Lookup and Unwind [duplicate]MongoDB聚合查找和展开[重复]
【发布时间】:2019-03-04 20:26:19
【问题描述】:

我有这个问题:

我需要进行查询,获取外部数据(通过查找)、“多对多”和“一对多”。

我的数据看起来是这样的:

转让收藏:

{
  "_id": 1,
  "requests": [
    {
       "service": 1,
       "foo": "foo1",
       "bar": "bar1"
    },
    {
       "service": 2,
       "foo": "foo2",
       "bar": "bar2"
    }
  ]
}

所以,“service”字段,是另一个集合“services”的外部ID。

服务集合:

[{ _id: 1, name: 'Service 1" }, { _id: 2, name: 'Service 2' }]

问题是:如何在 Transfer 集合中按服务名称进行过滤?我知道 mongoose 的填充,但这不允许通过外部数据进行过滤(另外,我的函数需要分页(我使用 mongoose-pagination 插件),因此,我在执行后丢弃过滤,因为这可以过滤少量数据宇宙)。

我相信最好的选择是使用聚合。 但是,如果我做这个......

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"
        }
      ]
}

【问题讨论】:

  • 所以您正试图让服务名称包含在每个 request 对象中?

标签: node.js mongodb mongoose aggregation-framework lookup


【解决方案1】:

这是一种解决方案 - 现在不确定它是否是最漂亮的,但它确实可以完成工作:

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" ] } }
                    ]
                }
            }
        }
    }
}])

我从未真正比较过这两个版本的性能,但我怀疑第二个版本要快一些。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-30
    • 1970-01-01
    • 2019-10-25
    • 2018-01-23
    相关资源
    最近更新 更多