Javascript 基于单个用户对从MongoDB集合中删除记录

Javascript 基于单个用户对从MongoDB集合中删除记录,javascript,arrays,mongodb,sorting,Javascript,Arrays,Mongodb,Sorting,我在MongoDB集合中有一组文档(消息),如下所示。我只想为单个用户对保留最新的500条记录。用户标识为sentBy和sentTo /* 1 */ { "_id" : ObjectId("5f1c1b00c62e9b9aafbe1d6c"), "sentAt" : ISODate("2020-07-25T11:44:00.004Z"), "readAt" : ISODat

我在MongoDB集合中有一组文档(消息),如下所示。我只想为单个用户对保留最新的500条记录。用户标识为
sentBy
sentTo

/* 1 */
{
    "_id" : ObjectId("5f1c1b00c62e9b9aafbe1d6c"),
    "sentAt" : ISODate("2020-07-25T11:44:00.004Z"),
    "readAt" : ISODate("1970-01-01T00:00:00.000Z"),
    "msgBody" : "dummy text",
    "msgType" : "text",
    "sentBy" : ObjectId("54d6732319f899c704b21ef7"),
    "sentTo" : ObjectId("54d6732319f899c704b21ef5"),
}

/* 2 */
{
    "_id" : ObjectId("5f1c1b3cc62e9b9aafbe1d6d"),
    "sentAt" : ISODate("2020-07-25T11:45:00.003Z"),
    "readAt" : ISODate("1970-01-01T00:00:00.000Z"),
    "msgBody" : "dummy text",
    "msgType" : "text",
    "sentBy" : ObjectId("54d6732319f899c704b21ef9"),
    "sentTo" : ObjectId("54d6732319f899c704b21ef8"),
}

/* 3 */
{
    "_id" : ObjectId("5f1c1b78c62e9b9aafbe1d6e"),
    "sentAt" : ISODate("2020-07-25T11:46:00.003Z"),
    "readAt" : ISODate("1970-01-01T00:00:00.000Z"),
    "msgBody" : "dummy text",
    "msgType" : "text",
    "sentBy" : ObjectId("54d6732319f899c704b21ef6"),
    "sentTo" : ObjectId("54d6732319f899c704b21ef8"),
}

/* 4 */
{
    "_id" : ObjectId("5f1c1c2e1449dd9bbef28575"),
    "sentAt" : ISODate("2020-07-25T11:49:02.012Z"),
    "readAt" : ISODate("1970-01-01T00:00:00.000Z"),
    "msgBody" : "dummy text",
    "msgType" : "text",
    "sentBy" : ObjectId("54cfcf93e2b8994c25077924"),
    "sentTo" : ObjectId("54d6732319f899c704b21ef5"),
}

/* and soon... assume it to be 10k+ */
我想到的算法是-

  • 首先基于OR运算符进行分组
  • 及时按降序排列记录
  • 限制在500
  • 获取应保留的
    \u id
    数组
  • 使用
    $nin
    条件将ID传递给新的mongo查询
    .deleteMany()

请帮助我在这方面做了很多努力,但没有取得任何成功。非常感谢:)

根据规模,我将执行以下两种操作之一:

  • 假设规模有点小,并且您可以在合理的时间内对整个集合进行分组,我会做一些类似于您建议的事情:
  • 由于无法对内部数组post组进行排序,因此排序阶段必须放在第一位,组阶段中的
    $cond
    模拟
    $或
    运算符逻辑,在那里无法使用。最后,与使用
    deleteMany
    $nin
    来检索结果不同,您只需使用重写当前集合即可

  • 如果规模太大,无法支持此功能,那么您应该逐个用户进行迭代,并按照您最初的建议进行操作,下面是一个快速示例:
  • 
    让userIds=wait db.collection.distinct(“sentBy”);
    完成=[1];
    for(设i=0;i
    实际上,我主要关心的是使用或条件分组。我喜欢你在第一个案例中的处理方式。第二个对我来说是新的,我也会试试这个。非常感谢,汤姆。
    db.collection.aggregate([
        {
            $sort: {
                sentAt: 1
            }
        },
        {
            $group: {
                _id: {
                    $cond: [
                        {$gt: ["$sentBy", "$sentTo"]},
                        ["$sendBy", "$sentTo"],
                        ["$sentTo", "$sendBy"],
                    ]
                },
                roots: {$push: "$$ROOT"}
            }
        },
        {
            $project: {
                roots: {$slice: ["$roots", -500]}
            }
        },
        {
            $unwind: "$roots"
        },
        {
            $replaceRoot: {
                newRoot: "$roots"
            }
        },
        {
            $out: "this_collection"
        }
    ])
    
    
    let userIds = await db.collection.distinct("sentBy");
    
    let done = [1];
    for (let i = 0; i < userIds.length; i++) {
        
        let matches = await db.collection.aggregate([
            {
                $match: {
                    $and: [
                        {
                            $or: [
                                {
                                    "sentTo": userIds[i]
                                },
                                {
                                    "sendBy": userIds[i]
                                }
                            ]
                        },
                        {  // this is not necessary it's just to avoid running on ZxY and YxZ 
                            $or: [
                                {
                                    sendTo: {$nin: done}
                                },
                                {
                                    sendBy: {$nin: done}
                                }
                            ]   
                        }
                    ]
                }
            },
            {
                $sort: {
                    sentAt: 1
                }
            },
            {
                $group: {
                    _id: {
                        $cond: [
                            {$eq: ["$sentBy", userIds[i]]},
                            "$sendTo",
                            "$sentBy"
                        ]
                    },
                    roots: {$push: "$$ROOT"}
                }
            },
            {
                $project: {
                    roots: {$slice: ["$roots", -500]}
                }
            },
            {
                $unwind: "$roots"
            },
            {
                $group: {
                    _id: null,
                    keepers: {$push: "$roots._id"}
                }
            }
        ]).toArray();
        
        if (matches.length) {
            await db.collection.deleteMany(
                {
                    $and: [
                        {
                            $or: [
                                {
                                    "sentTo": userIds[i]
                                },
                                {
                                    "sendBy": userIds[i]
                                }
                            ]
                        },
                        {  // this is only necessary if you used it above.
                            $or: [
                                {
                                    sendTo: {$nin: done}
                                },
                                {
                                    sendBy: {$nin: done}
                                }
                            ]
                        },
                        {
                            _id: {$nin: matches[0].keepers}
                        }
                    ]
                }
            )
        }
        
        done.push(userIds[i])
    }