首页 > 解决方案 > 选择要从 $lookup 返回的字段

问题描述

我有一段代码可以将集合 A(样本)加入集合 B(定位器)。我已经尝试过$unwind,$group$push语法,唯一的问题是我无法返回字段locatorrecord.


data = db.sample.aggregate([
{'$lookup': {
    'from': 'locators',
    'localField': "locator",
    'foreignField': "_id",
    'as': "metalocator"}}])

print(list(data))

哪个返回

[
  {
    '_id': '599A65E1A80541BA',
    'locator': 'ABC',
    'record': 'Nicaragua',
    'metalocator': [{'_id': 'ABC', 'group': 'Location', 'section': 'Geo', 'cabinet': 'Country', 'record': 'string', 'status': 'integer'}]
  },
  { 
    '_id': '428E970995AE8C76',
    'locator': 'CDE',
    'record': 'Nigeria',
    'metalocator': [{'_id': 'CDE', 'group': 'Location', 'section': 'Geo', 'cabinet': 'Country', 'record': 'string', 'status': 'integer'}]
  }
]

尝试 1

data = db.sample.aggregate([
    {"$lookup": {"from": "locators",
                 "localField": "locator",
                 "foreignField": "_id",
                 "as": "metalocator"}},
    {"$unwind": '$metalocator'},
    {"$group": {"_id": "$_id",
                "metalocator": {"$push":  {
                    "section": "$metalocator.section",
                    "cabinet": "$metalocator.cabinet"}}}}
])
print(list(data))

返回:

[
  {
    '_id': '1835853D2982AAEF',
    'metalocator': [{'section': 'Geo', 'cabinet': 'Country'}]
  },
  {
    '_id': '428E970995AE8C76',
    'metalocator': [{'section': 'Geo', 'cabinet': 'Country'}]
  }
]

预期结果应该是:

[
  {
    '_id': '1835853D2982AAEF',
    'locator': 'ABC',
    'record': 'Nicaragua',
    'metalocator': [{'section': 'Geo', 'cabinet': 'Country'}]
  },
  {
    '_id': '428E970995AE8C76',
    'locator': 'CDE',
    'record': 'Nigeria',
    'metalocator': [{'section': 'Geo', 'cabinet': 'Country'}]
  }
]

标签: pythonmongodbaggregation-frameworkpymongo

解决方案


你想要$map

db.sample.aggregate([
  {'$lookup': {
    'from': 'locators',
    'localField': "locator",
    'foreignField': "_id",
    'as': "metalocator"
  }},
  { '$addFields': {
    'metalocator': {
      '$map': {
        'input': '$metalocator',
        'in': {
          'section': '$$this.section',
          'cabinet': '$$this.cabinet'
        }
      }
    }
  }}
 ])

这就是您用来“重新映射”数组内容的方法,这正是您要问的。它的用法与 python 以及许多其他语言中的同名运算符非常相似。

如果您有 MongoDB 3.6,则可以交替使用不同的$lookup语法,您可以实际“选择”从那里返回哪些字段:

db.sample.aggregate([
  {'$lookup': {
    'from': 'locators',
    'let': { 'locator': '$locator' },
    'pipeline': [
      { '$match': {
        '$expr': { '$eq': [ '$_id', '$$locator' ] }
      }},
      { '$project': { 'section': 1, 'cabinet': 1, '_id': 0 } }
    ],
    'as': "metalocator"
  }}
])

这实际上会更有效,因为数据甚至不会返回到目标数组中,并且您不需要“重新映射”数组以丢弃其他字段。

为了记录,您“错过”的是$first操作员:

db.sample.aggregate([
  { "$lookup": {
    "from": "locators",
    "localField": "locator",
    "foreignField": "_id",
    "as": "metalocator"
  }},
  { "$unwind": '$metalocator'},
  { "$group": {
    "_id": "$_id",
    "locator": { "$first": "$locator" },
    "record": { "$first": "$record" },
    "metalocator": {
      "$push":  {
        "section": "$metalocator.section",
        "cabinet": "$metalocator.cabinet"
      }
    }
  }}
])

但是这里不需要使用$unwindand ,因为上面显示的其他方法效率更高。$group


推荐阅读