【问题标题】:MongoDB Aggregate is not matching specific fieldMongoDB 聚合与特定字段不匹配
【发布时间】:2021-04-07 13:54:43
【问题描述】:

我是 MongoDB 中 Aggregation 的新手,我试图通过举例来理解它的概念。

我正在尝试使用聚合对子文档进行分页,但返回的文档始终是所有文档特定字段的整体值。

我想对包含对象 ID 数组的 following 字段进行分页。

我有这个用户架构:

const UserSchema = new mongoose.Schema({
    username: {
        type: String,
        unique: true,
        required: true
    },
    firstname: String,
    lastname: String,
    following: [{
        type: mongoose.Schema.Types.ObjectId,
        ref: 'User'
    }],
    ...
}, { timestamps: true, toJSON: { virtuals: true }, toObject: { getters: true, virtuals: true } });

没有聚合,我可以分页following, 我有这条路线可以通过username获取用户的帖子

router.get(
    '/v1/:username/following',
    isAuthenticated,
    async (req, res, next) => {
        try {
            const { username } = req.params;
            const { offset: off } = req.query;

            let offset = 0;
            if (typeof off !== undefined && !isNaN(off)) offset = parseInt(off);

            const limit = 2;
            const skip = offset * limit;

            const user = await User
                .findOne({ username })
                .populate({
                    path: 'following',
                    select: 'profilePicture username fullname',
                    options: {
                        skip,
                        limit,
                    }
                })

          
            res.status(200).send(user.following);
        } catch (e) {
            console.log(e);
            res.status(500).send(e)
        }
    }
);

我使用聚合的分页版本:

const following = await User.aggregate([
                {
                    $match: { username }
                },
                {
                    $lookup: {
                        'from': User.collection.name,
                        'let': { 'following': '$following' },
                        'pipeline': [
                            {
                                $project: {
                                    'fullname': 1,
                                    'username': 1,
                                    'profilePicture': 1
                                }
                            }
                        ],
                        'as': 'following'
                    },
                }, {
                    $project: {
                        '_id': 0,
                        'following': {
                            $slice: ['$following', skip, limit]
                        }
                    }
                }
            ]);

假设我有这些文件:

[
                {
                    _id: '5fdgffdgfdgdsfsdfsf',
                    username: 'gagi',
                    following: []
                },
                {
                    _id: '5fgjhkljvlkdsjfsldkf',
                    username: 'kuku',
                    following: []
                },
                {
                    _id: '76jghkdfhasjhfsdkf',
                    username: 'john',
                    following: ['5fdgffdgfdgdsfsdfsf', '5fgjhkljvlkdsjfsldkf']
                },
            ]

当我为用户 john:/john/following 测试我的路线时,一切都很好,但是当我测试没有任何以下内容的不同用户时:/gagi/following,返回的结果与 john 的以下聚合相同似乎与用户名不匹配。

/john/following |以下:2

/kuku/following |以下:0

汇总结果:

[
  {
    _id: '5fdgffdgfdgdsfsdfsf',
    username: 'kuku',
    ...
  }, 
  {
    _id: '5fgjhkljvlkdsjfsldkf',
    username: 'gagi',
    ...
  }
]

我希望/kuku/following 返回一个空数组 [] 但结果与 john 的相同。实际上,我测试的所有用户名都返回相同的结果。

我认为我的实现一定有问题,因为我才开始探索聚合。

【问题讨论】:

    标签: javascript mongodb mongoose aggregate


    【解决方案1】:

    Mongoose 使用DBRef 能够在检索到该字段后填充该字段。
    DBRefs 只在客户端处理,MongoDB 聚合没有任何操作符来处理这些。

    聚合管道返回所有用户的原因是查找的管道没有匹配阶段,因此集合中的所有文档都被选中并包含在查找中。

    那里的示例文档显示了一个字符串数组而不是 DBRefs,这不适用于populate

    基本上,您必须决定是要使用聚合还是填充来处理连接。

    对于填充,请使用 ref,如示例架构中所示。

    对于聚合,存储一个 ObjectId 数组,以便您可以使用查找链接到 _id 字段。

    【讨论】:

    • 啊。知道了。所以管道确实没有执行匹配,但是可以在管道中添加 $match 阶段吗?我使用的IDs 只是为了演示而随机输入的字符,但它们在我的代码中是真正的 ObjectID,并且可以完美地填充并且无需聚合即可进行分页。只是试图通过使用聚合进行分页来理解聚合。
    • 如果它适用于populate,则该字段包含DBRefs 而不是ObjectIds,因此它不适用于聚合
    • 所以我必须将每个用户的 _id 设置为 ObjectID 之类的 "_id": { "$oid": "5feec0f2cce7f8b1105142e4" } 以便在这种情况下进行聚合?
    • 啊,明白了。现在一切都说得通了。以前不知道 DBRef 和 Manual ref 的东西。感谢您清理一切。
    猜你喜欢
    • 2021-08-08
    • 1970-01-01
    • 2020-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-22
    • 1970-01-01
    相关资源
    最近更新 更多