Mongodb子文档之间的多对多关系 [英] Mongodb many to many relations among sub-documents

查看:232
本文介绍了Mongodb子文档之间的多对多关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

TL; DR :想象一下,第一个$ match阶段为您提供了多个文档,但是您想像$redact一样在其中细化.但是问题是您的子文档之间有关系,并且您想使$where像它们之间的检查一样.一个人怎么能做到这一点? 我不能$ unwind,因为这会导致性能问题(1.5 mb的文档是数组长度的5倍,即1000个数组长度,一次展开会导致1000x〜1mb的文档).

TL;DR: Imagine first $match stage gave you several documents, but you want to refine them inside, like $redact does. But the problem is your sub-documents have relations, and you want to make $where like checks among them. How can one accomplish that? I cannot $unwind, because it is causing performance problems, (1.5 mb of document with 5 times 1000 array length, a single unwind is causing 1000x~1mb documents).

我的架构如下:

{
    userName: "user44",
    userID: "44",
    posts : [
        ...
        {
            title : "post1",
            id : "123"
            ...
        },
        {
            title : "post2",
            id : "124"
            ...
        },
        ...
    ],
    comments: [
        ...
        {
            id: "1910",
            postId : "123",
            commentTitle : "comment1",
            comment : "some comment",
            user: "user13"
        },
        {
            id: "1911",
            postId : "124",
            title : "comment2",
            commentTitle : "some comment",
            user: "user22"
        },
        {
            id: "1912",
            postId : "124",
            title : "comment2",
            commentTitle : "some comment",
            user: "user22"
        },
        ...
    ], 
    commentUpvotes: [
        ...
        {
            id : 12,
            commentId : "1910",
            upvotedBy: "user91",
            upvoteDate: 1000,         
        },
        {
            id: 13,
            commentId : "1910",
            upvotedBy: "user92",
            upvoteDate: 2000
        },
        {
            id: 14,
            commentId : "1911",
            upvotedBy: "user92",
            upvoteDate: 2100
        },
        ...
    ]
} 

尽管这与我的数据库无关,但是原始架构与上面的完全相同.因此,上面的示例是一个用户集合,我在其中存储了用户的postscomments由其他用户撰写的帖子,commentUpvotes用于存储有关谁投票的信息. 不要考虑其设计和开发的逻辑内容;我已经整理好了,请不要提出其他任何模式.

Although this has nothing to do with my database, original schema is exactly as above. So, this example above is a user collection, where I store posts of the user; comments that made to the posts by other users, commentUpvotes to store information about who upvoted. Don't think about the logic of its design & contents; I made them up, and please don't suggest any other schema.

问题:我正在寻找一种方法,以查找在特定日期(例如

Question: I am looking a way to find posts and comments which has upvoted after a specific date, such

 db.users.find("commentUpvotes.upvoteDate" : {$gte:0})

和结果:

{
    "_id" : ObjectId("539065d3cd0f2aac5f55778e"),
    "posts" : [
        {
            title : "post1",
            id : "123"
            ...
        },
        {
            title : "post2",
            id : "124"
            ...
        },
    ],
    "comments" : [
            {
            id: 1910,
            postId : "123",
            title : "comment1",
            comment : "some comment",
            user: "user13"
        },
        {
            id: 1911,
            postId : "124",
            title : "comment2",
            comment : "some comment",
            user: "user22"
        },
    ],
    "commentUpVotes" : [
            {
            id : 12,
            commentId : "1910",
            upvotedBy: "user91",
            upvoteDate: 1000,         
        },
        {
            id: 13,
            commentId : "1910",
            upvotedBy: "user92",
            upvoteDate: 2000
        },
        {
            id: 14,
            commentId : "1911",
            upvotedBy: "user92",
            upvoteDate: 2100
        }
    ]
}

注意:这是一个后问题,可以找到前一个问题

NOTE: It is a post-question, and former one can be found here. I wanted to extend it a bit in this one.

推荐答案

我找到了一种无需使用$ unwind和$redact + $$ROOT即可使其工作的方法.如您所知,$ redact会从父级到子级扫描文档,因此要在子文档中进行比较,我需要使用$$ ROOT.

I found a way to make it work without using $unwind and with $redact + $$ROOT. As you know $redact scans the document from parent to child, therefore to make comparison among subdocuments I needed to use $$ROOT.

由于仅在文档内部进行处理,因此我认为这是最有效的方法.如果有人提出更好的方法,我仍然会很高兴. $ redact上的资源并不多,我相信下面的代码仍然可以改进:

Since it is only processed inside of the document, I believe this is the most efficient way. I will still be glad if some propose better ways. There are not many resources on $redact, and I believe the code below still can be improved:

// first query match
{
    "$match": {
        "commentUpvotes.upvoteDate": {
            "$gte": 0
        }
    }
},
// exclude commentUpvotes
{
    $redact: {
        $cond: {
            if: {
                $or: [
                    {
                        $gte: [
                            "$upvoteDate",
                            0
                        ]
                    },
                    {
                        $not: "$upvoteDate"
                    }
                ]
            },
            then: "$$DESCEND",
            else: "$$PRUNE"
        }
    }
},
// exclude comments
{
    $redact: {
        $cond: {
            if: {
                $or: [
                    {
                        $not: "$postId"
                    },
                    {
                        $anyElementTrue: { $map: {
                                input: "$$ROOT.commentUpvotes",
                                as: "el",
                                in: { $cond: { if: { $eq: [  "$$el.commentId",  "$id" ] },
                                        then: true, else: false
                                    }
                                }
                            }
                        }
                    }
                ]
            },
            then: "$$DESCEND",
            else: "$$PRUNE"
        }
    }
},
// exclude posts
{
    $redact: {
        $cond: {
            if: {
                $or: [
                    {
                        $not: "$title"
                    },
                    {
                        $anyElementTrue: {
                            $map: {
                                input: "$$ROOT.comments",
                                as: "el",
                                in: {
                                    $cond: {
                                        if: {
                                            $eq: [
                                                "$$el.postId",
                                                "$id"
                                            ]
                                        },
                                        then: true,
                                        else: false
                                    }
                                }
                            }
                        }
                    }
                ]
            },
            then: "$$DESCEND",
            else: "$$PRUNE"
        }
    }
}

这篇关于Mongodb子文档之间的多对多关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆