推送前mongodb聚合修改元素

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了推送前mongodb聚合修改元素相关的知识,希望对你有一定的参考价值。

我正在尝试使用doctrine mongodb在mongodb上进行聚合查询。

这是我要查询的文件的简化版本:

{
    "_id" : ObjectId("574edf0ece8300c95ae0a1a4"),
    "user" : {
        "$ref" : "User",
        "$id" : ObjectId("574eac76ce8300a251e0a1a4"),
        "$db" : "master"
    },
    "content" : "some text",
    "hash" : "f46fe1003204704ce11edb15ff4b0ca3f93232da",
    "servicesToPublish" : [ 
        {
            "serviceTokenId" : "53931163ce830032106dfa6f",
            "status" : "published",
            "statusUpdatedAt" : ISODate("2016-06-01T13:12:17.000Z"),
            "type" : "text"
        }
    ]
}

这是我正在使用的查询:

$aggregationBuilder
    ->match()
        ->field('servicesToPublish.status')->equals(ServiceToPublish::STATUS_PUBLISHED)
        ->field('user.$id')->in($userIds)
    ->group()
        ->field('_id')->expression('$hash')
        ->field('posts')->push($aggregationBuilder->expr()->ifNull('$servicesToPublish', '[]'))
        ->field('users')->push('$users')
;

转换为这个mongo查询:

db.message.aggregate([{
    "$match": {
        "servicesToPublish.status": "published",
        "user.$id": {
            "$in": [ObjectId("5a733013ce8300b566d15a9b"),...]
        }
    }
}, {
    "$group": {
        "_id": "$hash",
        "posts": {"$push": "$servicesToPublish"},
        "users": {"$push": "$user"}
    }
}]);

这是一个示例结果

{
    "_id" : "19a5a9315ba8ac5ffb3779e68b887c805c61d54c",
    "posts" : [ 
        [ 
            {
                "serviceTokenId" : "5a7abe9cce8300c502f38d6c",
                "type" : "text",
                "status" : "published",
                "statusUpdatedAt" : ISODate("2018-04-17T08:20:02.000Z")
            }, 
            {
                "serviceTokenId" : "59c14d0ece83008449843d15",
                "type" : "other",
                "status" : "published",
                "statusUpdatedAt" : ISODate("2018-04-17T08:20:04.000Z")
            }
        ], 
        [ 
            {
                "serviceTokenId" : "59c13700ce83005a66843d15",
                "type" : "text",
                "status" : "published",
                "statusUpdatedAt" : ISODate("2018-04-17T06:21:57.000Z")
            }, 
            {
                "serviceTokenId" : "59c13725ce83005668843d15",
                "type" : "other",
                "status" : "published",
                "statusUpdatedAt" : ISODate("2018-04-17T06:21:59.000Z")
            }
        ]
    ],
    "user" : [ 
        {
            "$ref" : "User",
            "$id" : ObjectId("5a733013ce8300b566d15aa4"),
            "$db" : "master"
        }, 
        {
            "$ref" : "User",
            "$id" : ObjectId("5a7abc2ece83003b6af38d6c"),
            "$db" : "master"
        }
    ]
}

我需要保持userposts之间的关联,有没有办法使用用户id作为post数组中的键(类似这样:"posts": {"id1":[...], "id2": [...]})或将用户id添加到posts数组的每个元素中,如{"userId":"...", "serviceTokenId" : "...","type":"...", "status":"...", "statusUpdatedAt":ISODate("...")}


如果没有办法做到这一点,我可以确定posts数组的顺序是否与用户相同? (即posts的第一个元素对应于user的第一个元素)

答案

您可以使用新的$addFields阶段将用户添加到帖子中。

在简单的mongodb查询中,它将如下所示:

db.message.aggregate([
{
    "$match": {
        "servicesToPublish.status": "published",
        "user.$id": {
            "$in": [ObjectId("5a733013ce8300b566d15a9b"),...]
        }
    }
}, 
{
    "$addFields" : { servicesToPublish: { $map: { 
        input: "$servicesToPublish", 
        as: "service", 
        in: { $mergeObjects: [ "$$service", { user: "$user" } ] }
    } } }
},
{
    "$group": {
        "_id": "$hash",
        "posts": {"$push": "$servicesToPublish"},
        "user": {"$push": "$user"}
    }
}
]);

哪个应该给你这样的东西:

{
    "_id" : "19a5a9315ba8ac5ffb3779e68b887c805c61d54c",
    "posts" : [ 
        [ 
            {
                "serviceTokenId" : "5a7abe9cce8300c502f38d6c",
                "type" : "text",
                "status" : "published",
                "statusUpdatedAt" : ISODate("2018-04-17T08:20:02.000Z"),
                "user" : {
                    "$ref" : "User",
                    "$id" : ObjectId("5a733013ce8300b566d15aa4"),
                    "$db" : "master"
                }
            }, 
            {
                "serviceTokenId" : "59c14d0ece83008449843d15",
                "type" : "other",
                "status" : "published",
                "statusUpdatedAt" : ISODate("2018-04-17T08:20:04.000Z")
                "user" : {
                    "$ref" : "User",
                    "$id" : ObjectId("5a733013ce8300b566d15aa4"),
                    "$db" : "master"
                }
            }
        ], 
        [ 
            {
                "serviceTokenId" : "59c13700ce83005a66843d15",
                "type" : "text",
                "status" : "published",
                "statusUpdatedAt" : ISODate("2018-04-17T06:21:57.000Z")
                "user" : {
                    "$ref" : "User",
                    "$id" : ObjectId("5a7abc2ece83003b6af38d6c"),
                    "$db" : "master"
                }
            }, 
            {
                "serviceTokenId" : "59c13725ce83005668843d15",
                "type" : "other",
                "status" : "published",
                "statusUpdatedAt" : ISODate("2018-04-17T06:21:59.000Z")
                "user" : {
                    "$ref" : "User",
                    "$id" : ObjectId("5a7abc2ece83003b6af38d6c"),
                    "$db" : "master"
                }
            }
        ]
    ],
    "user" : [ 
        {
            "$ref" : "User",
            "$id" : ObjectId("5a733013ce8300b566d15aa4"),
            "$db" : "master"
        }, 
        {
            "$ref" : "User",
            "$id" : ObjectId("5a7abc2ece83003b6af38d6c"),
            "$db" : "master"
        }
    ]
}

由于您在字段名称中使用带有$的DBRef,因此无法单独获取userId。尝试使用它像{ $mergeObjects: [ "$$services", { userId: "$user.$id" } ] }导致错误16410“FieldPath字段名称可能不以'$'开头。”

以上是关于推送前mongodb聚合修改元素的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB聚合推送索引

使用 MongoDb 聚合管道根据特定类型查询前 10 项

MongoDB:使用正则表达式聚合数组元素

Mongodb聚合:投影没有最后一个元素的数组

MongoDB聚合:计算数组元素或距离之间的差异

MongoDB聚合,如何在组管道中addToSet数组的每个元素