如何在MongoDB中将数组位置$与聚合投影一起使用

时间:2018-10-14 17:55:48

标签: mongodb aggregation-framework

revisions是一个对象(键为entryId)时,我有一个正在运行的聚合调用。

await Project.aggregate([
  { $limit: 1 },
  { $match: { _id: ObjectId(projectId) } },
  {
    $project: {
      limits: 1,
      revisions: { $slice: [`$revisions.${entryId}.${languageId}`, startIndex, PageSize] },
      totalRevisions: {
        $size: { $ifNull: [`$revisions.${entryId}.${languageId}`, []] },
      },
    },
  },
]);

现在,我将revisions转换为其中包含entryId的数组,我不确定如何获得相同的结果。我尝试过:

await Project.aggregate([
  { $limit: 1 },
  {
    $match: {
      _id: ObjectId(projectId),
      'revisions.entryId': ObjectId(entryId),
    },
  },
  {
    $project: {
      limits: 1,
      revisions: { $slice: [`$revisions.$.${languageId}`, startIndex, PageSize] },
      totalRevisions: {
        $size: { $ifNull: [`$revisions.$.${languageId}`, []] },
      },
    },
  },
]);

但是我得到了错误:

  

MongoError:FieldPath字段名称不能以“ $”开头。

如何对数组中的项目使用$slice$ifNull?谢谢

示例文档:

{
  "revisions" : [ 
    {
      "entryId" : ObjectId("5bbf8813c272e05171463bc4"),
      "5bbe76c6d3fb1a4f143f8304" : [ 
        {
          "authorId" : ObjectId("5b1c5384d75d9f3b0eb65c2a"),
          "revisionId" : ObjectId("5bbf8813c272e05171463bc7"),
          "updated" : "2018-10-11T17:27:47.842Z",
          "value" : "County"
        }
      ]
    }
  ]
}

1 个答案:

答案 0 :(得分:1)

管道阶段的顺序在这里确实很重要。在$limit之前使用$match时,它将过滤$limit阶段中找到的单个文档中的数据。

如果您将在$match之前使用$limit,那么它将从数据库内的所有集合中过滤文档,并在$limit阶段抛出单个文档。

之后,您可以尝试以下汇总

db.collection.aggregate([
  { "$match": {
    "_id": ObjectId(projectId),
    "revisions.entryId": ObjectId(entryId)
  }},
  {
    "$project": {
      "revisions": {
        "$map": {
          "input": "$revisions",
          "in": {
            "$arrayToObject": {
              "$map": {
                "input": {
                  "$filter": {
                    "input": { "$objectToArray": "$$this" },
                    "as": "ee",
                    "cond": { "$eq": ["$$ee.k", "5bbe76c6d3fb1a4f143f8304"] }
                  }
                },
                "as": "dd",
                "in": {
                  "k": "$$dd.k",
                  "v": { "$slice": [startIndex, 1 ] }
                }
              }
            }
          }
        }
      },
      "totalRevisions": {
        "$arrayElemAt": [
          {
            "$map": {
              "input": "$revisions",
              "in": {
                "$size": {
                  "$map": {
                    "input": {
                      "$filter": {
                        "input": { "$objectToArray": "$$this" },
                        "as": "ee",
                        "cond": { "$eq": ["$$ee.k", "5bbe76c6d3fb1a4f143f8304"] }
                      }
                    },
                    "as": "dd",
                    "in": {
                      "k": "$$dd.k",
                      "v": { "$slice": [startIndex, 1] }
                    }
                  }
                }
              }
            }
          },
          0
        ]
      }
    }
  }
])

但是,如果您刚开始您的项目,那么我强烈建议您不要使用这种结构,因为您的嵌套数组键是动态的,并且使用动态键总是像在裸电线上玩一样。