代码之家  ›  专栏  ›  技术社区  ›  Ninja Warrior 11

选择要从$lookup返回的字段

  •  2
  • Ninja Warrior 11  · 技术社区  · 8 年前

    我有一段代码将集合A(示例)连接到集合B(定位器)。我试过了 $unwind , $group $push 语法唯一的问题是我不能返回字段 locator record .


    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'}]
      }
    ]
    
    1 回复  |  直到 8 年前
        1
  •  3
  •   Neil Lunn    8 年前

    你想要的 $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"
          }
        }
      }}
    ])
    

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