如果直接从查询返回文档,则不会调用 mongoose 模式转换

mongoose schema transform not invoked if document is returned directly from query

我有一个端点执行如下操作:

        const pipeline = [
          {
            $match: {
              $and: [
                {
                  $or: [...],
                },
              ],
            },
          },
          {
            $group: {
              _id : '$someProp',
              anotherProp: { $push: '$$ROOT' },
            },
          },
          { $sort: { date: -1 } },
          { $limit: 10 },
        ]
        const groupedDocs = await MyModel.aggregate(pipeline);

这里的想法是返回的文档如下所示:

[
  {
    _id: 'some value',
    anotherProp: [ /* ... array of documents where "someProp" === "some value" */ ],
  },
  {
    _id: 'another value',
    anotherProp: [ /* ... array of documents where "someProp" === "another value" */ ],
  },
  ...
]

得到这些结果后,端点返回一个包含anotherProp所有成员的数组,像这样:

const response = groupedDocs.reduce((docs, group) => docs.concat(group.anotherProp), []);
res.status(200).json(response);

我的问题是响应中的最终文档包含 _id 字段,但我想将该字段重命名为 idThis question addresses this issue, and specifically this answer 应该 工作的,但由于某种原因,转换函数没有被调用。换句话说,我试过这样做:

schema.set('toJSON', {
    virtuals: true,
    transform: function (doc, ret) {
        console.log(`transforming toJSON for document ${doc._id}`);
        delete ret._id;
    },
});
schema.set('toObject', {
    virtuals: true,
    transform: function (doc, ret) {
        console.log(`transforming toObject for document ${doc._id}`);
        delete ret._id;
    },
});

但是 console.log 语句没有执行,这意味着转换函数没有被调用。所以我仍然在响应中得到 _id 而不是 id.

所以我的问题是 在这种情况下我怎样才能得到 id 而不是 _id

值得一提的是,在我从文档中读取属性的其他地方调用了 toJSONtoObjectconsole.logs 显示)。就像我这样做:

const doc = await MyModel.findById('someId');
const name = doc.name;
res.status(200).json(doc);

响应包含 id 而不是 _id。这几乎就像一旦我对文档进行任何操作都会调用转换函数,但是如果我在文档从数据库到达时直接传递它们,则 toJSONtoObject 都不会被调用。

提前感谢您的见解。 :)

toJSONtoObject 方法在这里不起作用,因为它们不适用于聚合管道中的文档。 Mongoose 不会将聚合文档转换为 mongoose 文档,它 returns 管道操作返回的原始对象。我最终通过添加管道阶段来实现这一点,首先添加一个与 _id 字段具有相同值的 id 字段,然后第二个阶段删除 _id 字段。所以基本上我的管道变成了:

        const pipeline = [
          {
            $match: {
              $and: [
                {
                  $or: [...],
                },
              ],
            },
          },
          // change the "_id" to "id"
          { $addFields: { id: '$_id' } },
          { $unset: ['_id'] },
          {
            $group: {
              _id : '$someProp',
              anotherProp: { $push: '$$ROOT' },
            },
          },
          { $sort: { date: -1 } },
          { $limit: 10 },
        ]
        const groupedDocs = await MyModel.aggregate(pipeline);