首页 > 解决方案 > 嵌套值的 $sum 内的 $nin 条件

问题描述

我正在使用nodejsand制作聊天应用程序mongodb。目前我有多个用户、房间和消息的集合。每条消息都包含对房间、发件人的引用以及对已阅读该消息的用户的引用数组。

我正在尝试使用 mongodb 的聚合来获取当前用户的未读消息计数。这是我当前的代码:

Room.aggregate([
    {
        $match: { participants: request.currentUser._id },
    },
    {
        $lookup: {
            from: 'messages',
            localField: '_id',
            foreignField: 'room',
            as: 'messages',
        },
    },
    {
        $unwind: {
            path: '$messages',
            preserveNullAndEmptyArrays: true,
        },
    },
    {
        $sort: { 'messages.createdAt': -1 },
    },
    {
        $group: {
            _id: '$_id',
            name: { $first: '$name' },
            type: { $first: '$type' },
            participants: { $first: '$participants' },
            latestMessage: { $first: '$messages' },
            createdAt: { $first: '$createdAt' },
            updatedAt: { $first: '$updatedAt' },
            unreads: {
                $sum: {
                    $cond: {
                        if: {
                            $nin: [request.currentUser._id, '$messages.read']
                        }
                    }
                }
            },
        },
    },
])

此代码总是抛出Unrecognized expression '$nin'错误。我怎样才能在内部使用这样的条件$sum来获得适当的结果?

@Ashh 要求的示例消息文档:

{
    "_id" : ObjectId("5ef0796fdb424a92c4200cdd"),
    "read" : [ 
        ObjectId("5ef078df7ce82f2e5cf3b586")
    ],
    "content" : "Test message",
    "sender" : ObjectId("5ef078df7ce82f2e5cf3b586"),
    "room" : ObjectId("5ed4ffcdd13f45b4104a1669"),
    "createdAt" : ISODate("2020-06-22T09:27:11.017Z"),
    "updatedAt" : ISODate("2020-06-22T09:27:11.017Z")
}

还有一个样板间文件:

{
    "_id" : ObjectId("5ed4ffcdd13f45b4104a1669"),
    "participants" : [ 
        ObjectId("5ed4ffbcd13f45b4104a1667"), 
        ObjectId("5ef078df7ce82f2e5cf3b586")
    ],
    "pending" : [],
    "name" : "Global",
    "type" : "CHANNEL",
    "creator" : ObjectId("5ed4ffbcd13f45b4104a1667"),
    "createdAt" : ISODate("2020-06-01T13:17:01.935Z"),
    "updatedAt" : ISODate("2020-06-01T13:17:01.935Z")
}

标签: javascriptnode.jsmongodbmongoosenosql

解决方案


$nin不是聚合运算符,但是$in是,您可以使用反转逻辑$in

$cond有两种语法

{ $cond: { if: <boolean-expression>, then: <true-case>, else: <false-case> } }

{ $cond: [ <boolean-expression>, <true-case>, <false-case> ] }

我们需要用 0 替换真案例,用 1 替换假案例,因为我们将计算不在数组中的案例

        $sum: {
          $cond: [
            { $in: [request.currentUser._id, "$messages.read"] },
            0, // add 0 if in array
            1 // add 1 if not in array
          ]
        }

如果messages.read不存在,则会导致错误,因此您最好将其包装为$ifNull

        $sum: {
          $cond: [
            { $in: [request.currentUser._id, { $ifNull:[ "$messages.read", []] }] },
            0, // add 0 if in array
            1 // add 1 if not in array
          ]
        }

推荐阅读