查找对象数组

时间:2017-07-09 21:46:58

标签: mongodb mongoose mongodb-query aggregation-framework

我正在尝试填充我的文档中引用另一个集合的两个对象数组。然而,它总是在结果中显示为空数组,令我感到惊讶。我在这做错了什么?有没有更好的方法来“填充”uploaded_filesfile_history

这是我的汇总声明:

    Project.aggregate(
        { $match: {"project_id": projectId}},
        { $addFields: {
            uploaded_files: {
                $filter: {
                    input: '$uploaded_files',
                    as: 'uploadedFile',
                    cond: {$eq: ['$$uploadedFile.upload_id', uploadId]}
                }
            },
            file_history: {
                $filter: {
                    input: '$file_history',
                    as: 'revision',
                    cond: {$eq: ['$$revision.upload_id', uploadId]}
                }
            },
        }},
        { $lookup: {
            from: 'users',
            localField: 'owner',
            foreignField: '_id',
            as: 'owner'
        }},
        { $lookup: {
            from: 'files',
            localField: 'uploaded_files.file',
            foreignField: '_id',
            as: 'test'
        }},
        { $lookup: {
            from: 'files',
            localField: 'file_history.file',
            foreignField: '_id',
            as: 'test2'
        }},
        { $unwind: '$owner' },
        { $limit: 1 }
    ).then(projects => {
        if (projects.length == 0)
            return res.status(404).send({ error: "Couldn't find a project with this id" })

        let project = projects[0]
})

我的文档如下所示:

{
    "_id" : ObjectId("5935a41f12f3fac949a5f925"),
    "project_id" : 13,
    "updated_at" : ISODate("2017-07-09T19:41:51.396Z"),
    "created_at" : ISODate("2017-06-05T18:34:07.150Z"),
    "owner" : ObjectId("591eea4439e1ce33b47e73c3"),
    "name" : "Demo project",
    "uploaded_files" : [ 
        {
            "display_name" : "001.jpg",
            "file" : ObjectId("596286ff7d3a594ed4797848"),
            "upload_id" : ObjectId("596286ff7d3a594ed4797849"),
            "created_at" : ISODate("2017-07-09T19:41:51.000Z")
        }
    ],
    "file_history" : [ 
        {
            "display_name" : "001.jpg",
            "file" : ObjectId("596286ff7d3a594ed4797848"),
            "upload_id" : ObjectId("596286ff7d3a594ed4797849"),
            "created_at" : ISODate("2017-07-09T19:41:51.000Z")
        }
    ]
}

1 个答案:

答案 0 :(得分:1)

你首先需要$unwind数组。 MongoDB还不能使用" inner"数组中对象的属性,作为$lookup的源。

同样为了提高效率,我们首先应该使用$concatArrays来加入"加入"数组源,然后只执行一次 $lookup操作:

Project.aggregate([
  { "$match": { "project_id": projectId} },
  { "$project": {
    "project_id": 1,
    "updated_at": 1,
    "created_at": 1,
    "owner": 1,
    "name": 1,
    "combined": {
      "$concatArrays": [
        { "$map": {
          "input": {
            "$filter": {
              "input": "$uploaded_files",
              "as": "uf",
              "cond": { "$eq": ["$$uf.upload_id", uploadId ] }
            }
          },
          "as": "uf",
          "in": {
            "$arrayToObject": {
              "$concatArrays": [
                { "$objectToArray": "$$uf" },
                [{ "k": "type", "v": "uploaded_files" }]
              ]
            }
          }
        }},
        { "$map": {
          "input": {
            "$filter": {
              "input": "$file_history",
              "as": "fh",
              "cond": { "$eq": ["$$fh.upload_id", uploadId ] }
            }
          },
          "as": "fh",
          "in": {
            "$arrayToObject": {
              "$concatArrays": [
                { "$objectToArray": "$$fh" },
                [{ "k": "type", "v": "file_history" }]
              ]
            }
          }
        }}
      ]
    }
  }},
  { "$unwind": "$combined" },
  { "$lookup": {
    "from": "files",
    "localField": "combined.file",
    "foreignField": "_id",
    "as": "combined.file"
  }},
  { "$unwind": "$combined.file" },
  { "$lookup": {
    "from": "users",
    "localField": "owner",
    "foreignField": "_id",
    "as": "owner"
  }},
  { "$unwind": "$owner" },
  { "$group": {
    "_id": "$_id",
    "project_id": { "$first": "$project_id" },
    "updated_at": { "$first": "$updated_at" },
    "created_at": { "$first": "$created_at" },
    "owner": { "$first": "$owner" },
    "name": { "$first": "$name" },
    "combined": { "$push": "$combined" }
  }},
  { "$project": {
    "project_id": 1,
    "updated_at": 1,
    "created_at": 1,
    "owner": 1,
    "name": 1,
    "uploaded_files": {
      "$filter": {
        "input": "$combined",
        "as": "cf",
        "cond": { "$eq": [ "$$cf.type", "uploaded_files" ] }
      }    
    },
    "file_history": {
      "$filter": {
        "input": "$combined",
        "as": "cf",
        "cond": { "$eq": [ "$$cf.type", "file_history" ] }
      }    
    }
  }}
])

简而言之

  1. 将两个数组放在源上并标记它们,然后$unwind首先

  2. 对合并的详细信息$lookup和<{p>

  3. $unwind执行操作
  4. 执行其他外国来源的$lookup和<{p>

  5. $unwind
  6. $group将文档与单个数组一起返回。

  7. $filter由&#34;标记名称&#34;或&#34;键入&#34;我们添加到&#34;分离&#34;数组。

  8. 您可以按照相同的过程,只需在每个数组上使用$unwind,然后执行&#34; join&#34;并重新组合在一起。但真的需要更多的步骤,而不仅仅是#34;结合&#34;首先。

      

    另请注意,$lookup后跟$unwind实际上在服务器上处理时被视为一个管道阶段。有关详细信息,请参阅Aggregation Pipeline Optimization