MongoDB使用聚合

时间:2019-06-28 10:09:07

标签: mongodb

我有两个收藏集UserPost

用户

  • user_id
  • 地区
  • is_join

发布

  • post_id
  • user_id
  • 身体
  • is_block

从rdb的角度来看,User:Post关系为1:N。

每个user可以写多个post

例如,当前这样插入文档。

用户

> db.user.find()
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28d2"), "user_id" : NumberLong(1), "region" : "US", "is_join" : true }
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28d5"), "user_id" : NumberLong(2), "region" : "KR", "is_join" : true }
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28d8"), "user_id" : NumberLong(3), "region" : "US", "is_join" : true }
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28da"), "user_id" : NumberLong(4), "region" : "KR", "is_join" : false }
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28dc"), "user_id" : NumberLong(5), "region" : "US", "is_join" : true }

发布

> db.post.find()
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28d3"), "post_id" : NumberLong(1), "user_id" : NumberLong(1), "body" : "first", "is_block" : false }
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28d4"), "post_id" : NumberLong(4), "user_id" : NumberLong(1), "body" : "fourth", "is_block" : false }
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28d6"), "post_id" : NumberLong(2), "user_id" : NumberLong(2), "body" : "second", "is_block" : false }
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28d7"), "post_id" : NumberLong(3), "user_id" : NumberLong(2), "body" : "third", "is_block" : false }
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28d9"), "post_id" : NumberLong(5), "user_id" : NumberLong(3), "body" : "fifth", "is_block" : true }
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28db"), "post_id" : NumberLong(6), "user_id" : NumberLong(4), "body" : "sixth", "is_block" : false }
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28dd"), "post_id" : NumberLong(7), "user_id" : NumberLong(5), "body" : "seven", "is_block" : true }
{ "_id" : ObjectId("5d15e41a1b48d9417ebc28de"), "post_id" : NumberLong(8), "user_id" : NumberLong(5), "body" : "eight", "is_block" : false }

要通过聚集进行联接,还需要满足更多条件。

  1. 用户region='US'is_join=true
  2. 用户创建的帖子,结果为1
  3. 发布is_block=false
  4. post_id排序
  5. (可选)如果用户未写任何帖子,除非它。我知道它可以通过preserveNullAndEmptyArrays执行,但是我认为这会导致性能问题。

所需结果

{
    "posts" : [
        {
            "post_id" : NumberLong(1),
            "body" : "first",
            "is_block" : false
        },
        {
            "post_id" : NumberLong(2),
            "body" : "second",
            "is_block" : false
        },
        {
            "post_id" : NumberLong(3),
            "body" : "third",
            "is_block" : false
        },
        {
            "post_id" : NumberLong(4),
            "body" : "fourth",
            "is_block" : false
        },
        {
            "post_id" : NumberLong(8),
            "body" : "eight",
            "is_block" : false
        }
    ]
}

post_id = 5is_block=true排除

post_id = 6is_join=false排除

post_id = 7is_block=true排除

整个结果按post_id排序。

我是mongodb的新手,所以,也许我以关系数据库的形式想得太多。

我不知道它可以在NoSQL上执行。

有什么办法吗?

任何建议,非常感谢。

谢谢。

2 个答案:

答案 0 :(得分:1)

您可以使用查找管道运算符获得这种结果。

const region = 'US';
const is_join = true;
const is_block = false;
const query = [
    {
        $match: {
            region: region,
            is_join: is_join
        }
    },
    {
        $lookup: {
            let: { user_id: "$user_id" },
            from: 'posts',
            pipeline: [
                {
                    $match: {
                        $expr: {
                            $and: [
                                { $eq: ["$$user_id", "$user_id"], },
                                { $eq: ["$is_block", is_block] }
                            ]

                        }
                    }
                },
                {
                    $sort: {
                        post_id: 1
                    }
                }
            ],
            as: "posts"
        }
    },
    {
        $unwind: "$posts"
    },
    {
        $group:{
            _id: "mygroup",
            posts: { 
                $push: {
                    post_id: "$posts.post_id",
                    body: "$posts.body",
                    is_block: "$posts.is_block",
                }
            }
        }
    },
    {
        $project:{
            _id: false
        }
    }
]
db.users.aggregate(query)

输出

{
    "posts" : [
        {
            "post_id" : 1,
            "body" : "first",
            "is_block" : false
        },
        {
            "post_id" : 4,
            "body" : "fourth",
            "is_block" : false
        },
        {
            "post_id" : 8,
            "body" : "eight",
            "is_block" : false
        }
    ]
}

答案 1 :(得分:0)

尝试一下-

要加入两个集合,可以将聚合用作-

  User.aggregate([{
    '$match': { 'region':'US', 'is_join': true }  // match from users collection
  }, {
    $lookup: {             // it will aggregate the result from both collection
      from: 'posts',
      localField: '_id',
      foreignField: 'user_id',
      as: 'posts'
    }
  },
   {"$unwind":"$posts"},
   {$match : { "posts.is_block" : false } }, // check inside post collection
   {$sort : { "posts.post_id" : 1}},  // sort the data
 ], (err, users) => {
    if (err) return callback(err, null);

        console.log('users :', users);

  });