从$ Lookup在Mongodb中合并两个数组对象

时间:2018-12-28 17:49:59

标签: mongodb

我有两个Mongodb 3.6集合,其中一个引用另一个作为示例数据,其中certs.$Entities.Id: entities._id

certs: {
    _id: ObjectId('xxx'),
    Category: "Certification",
    Entities: [{Id: ObjectId('abc'), prev: true, Own_type: "Contact"}
              {Id: ObjectId('def), prev: false, Own_Type: "Operator"}]
    ...bunch more fields
}

另外一个:

entities: {_id: ObjectId('abc'), 
           FName: 'Bob', 
           LName: 'Smith', 
           ...bunch more fields}, 
          {_id: ObjectId('def'), 
           FName: 'Bill', 
           LName: 'Jones',
           ...bunch more fields}

我想使用一个简单的查询将信息从实体获取到证书中,通常会这样做,但是它会产生两个对象或覆盖cert.Entities。问题是我需要能够保留cert.Entities中的数据并将其与entities合并。

所需的结果将是:

certs: {
    _id: ObjectId('xxx'),
    Category: "Certification",
    Entities: [{Id: ObjectId('abc'), 
                prev: true, 
                Own_type: "Contact",
                FName: 'Bob', 
                LName: 'Smith', 
                ...bunch more fields}
              {Id: ObjectId('def), 
               prev: false, 
               Own_Type: "Operator",
               FName: 'Bill', 
               LName: 'Jones',
               ...bunch more fields
               }]
    ...bunch more fields
}

我通过执行以下聚合来完成此操作,但是看起来不对,因为我必须在结果中需要使用的多个字段上使用$ first累加器。

certs.aggregate([{
    $unwind: {
      path: '$Entities',
      preserveNullAndEmptyArrays: false
    }
  },
  {
    $lookup: {
      from: 'entities',
      localField: 'Entities.Id',
      foreignField: '_id',
      as: 'Ent'
    }
  },
  {
    $unwind: {
      path: '$Ent',
      preserveNullAndEmptyArrays: false
    }
  },
  {
    $addFields: {
      Ent2: {
        $mergeObjects: ['$Ent', '$Entities']
      }
    }
  },
  {
    $group: {
      _id: '$_id',
      Entities: {
        $push: '$Ent2'
      },
      Cert_ID: {
        $first: '$Cert_ID'
      },
      Cert_Details: {
        $first: '$Cert_Details'
      },
      Allocations: {
        $first: '$Allocations'
      },
      Flowmeters: {
        $first: '$Flowmeters'
      },
      Category: {
        $first: '$Category'
      },
      Water_Sources: {
        $first: '$Water_Sources'
      },
      Active: {
        $first: '$Active'
      },
      County: {
        $first: '$County'
      },
      Legal: {
        $first: '$Legal'
      },
      GWMA: {
        $first: '$GWMA'
      },
      Alias: {
        $first: '$Alias'
      },
      Usage: {
        $first: '$Usage'
      }
    }
  }])

有人可以给我一些建议以改善总体状况还是给我一个替代管道?

1 个答案:

答案 0 :(得分:0)

您需要$map$filter来替换$lookup之后的联接实体

db.certs.aggregate([
    {$match : {_id : "xxx"}}, 
    {$lookup : {from:"entities", localField:"Entities",foreignField:"_id", as: "joins"}},
    {$addFields : {Entities: 
        {$map : {
            input : "$Entities", 
            as : "e", 
            in : {$arrayElemAt :[{
                $filter : {
                    input : "$joins", 
                    as : "j", 
                    cond : {$eq :["$$e", "$$j._id"]}
                }},0]}
            }}
    }},
    {$project : {joins:0}}
]).pretty()

EDIT-1

保留两个数组元素中的字段

db.certs.aggregate([
    {$match : {_id : "xxx"}}, 
    {$lookup : {from:"entities", localField:"Entities._id",foreignField:"_id", as: "joins"}},
    {$addFields : {Entities: 
        {$map : {
            input : "$Entities", 
            as : "e", 
            in : {$mergeObjects: [
                "$$e",
                {$arrayElemAt :[{$filter : {input : "$joins",as : "j", cond : {$eq :["$$e", "$$j._id"]}}},0]}
                ]
            }}}
    }},
    {$project : {joins:0}}
]).pretty()