MongoDB 聚合与特定字段不匹配

Posted

技术标签:

【中文标题】MongoDB 聚合与特定字段不匹配【英文标题】:MongoDB Aggregate is not matching specific field 【发布时间】: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 的相同。实际上,我测试的所有用户名都返回相同的结果。

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

【问题讨论】:

【参考方案1】:

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

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

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

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

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

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

【讨论】:

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

以上是关于MongoDB 聚合与特定字段不匹配的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 $project 中提供的 _id 与 mongodb 聚合进行 $match?

使用 mongoDB 中的聚合删除集合中所有文档的特定字段

性能聚合 MongoDB 匹配和示例

如何仅在特定条件下执行 MongoDB 聚合阶段之一?

Mongodb 查找与聚合匹配返回一个空数组

MongoDB 查找与使用聚合指定的任何条件匹配的文档