MongoDB:如何检索新构建的数据而不是集合中的原始文档?

时间:2020-11-29 02:37:39

I have a collection in which documents are all in this format:

我有一个集合,其中的文档都是这种格式:

{"user_id": ObjectId, "book_id": ObjectId}

It represents the relationship between user and book, which is also one-to-many, that means, a user can have more than one books.

它表示用户和书籍之间的关系,也是一对多的关系,这意味着用户可以拥有多本书籍。

Now I got three book_id, for example:

现在我有三个book_id,例如:

["507f191e810c19729de860ea", "507f191e810c19729de345ez", "507f191e810c19729de860efr"]

I want to query out the users who have these three books, because the result I want is not the document in this collection, but a newly constructed array of user_id, it seems complicated and I have no idea about how to make the query, please help me.

我想查询拥有这三本书的用户,因为我想要的结果不是这个集合中的文档,而是一个新构造的user_id数组,看起来很复杂,我不知道如何进行查询,请帮我。

NOTE:

注意:

The reason why I didn't use the structure like:

我没有使用如下结构的原因:

{"user_id": ObjectId, "book_ids": [ObjectId, ...]}

is because in my system, books increase frequently and have no limit in amount, in other words, user may read thousands of books, so I think it's better to use the traditional way to store it.

因为在我的系统中,书籍频繁增加并且数量没有限制,换句话说,用户可能会阅读数千本书,所以我认为最好使用传统方式来存储它。

This question is not restricted by MongoDB, you can answer it in relational database thoughts.

这个问题不受MongoDB的限制,你可以在关系数据库的思想中回答它。

1 个解决方案

#1


2  

Using a regular find you cannot get back all user_id fields who own all the book_id's because you normalized your collection (flattened it).

使用常规查找,您无法获取拥有所有book_id的所有user_id字段,因为您对集合进行了规范化(将其展平)。

You can do it, if you use aggregation framework:

如果使用聚合框架,则可以执行此操作:

db.collection.aggregate([
    {
        $match: {
            book_id: {
                $in: ["507f191e810c19729de860ea",
                      "507f191e810c19729de345ez",
                      "507f191e810c19729de860efr" ]
            }
        }
    },
    {
        $group: {
            _id: "$user_id",
            count: { $sum: 1 }
        }
    },
    {
        $match: {
            count: 3
        }
    },
    {
        $group: {
            _id: null,
            users: { $addToSet: "$_id" }
        }
    }
]);

What this does is filters through the pipeline only for documents which match one of the three book_id values, then it groups by user_id and counts how many matches that user got. If they got three they pass to the next pipeline operation which groups them into an array of user_ids. This solution assumes that each 'user_id,book_id' record can only appear once in the original collection.

这样做只是为了匹配三个book_id值之一的文档过滤管道,然后按user_id分组并计算用户获得的匹配数。如果他们有三个,他们将传递给下一个管道操作,该操作将它们分组为user_id数组。此解决方案假定每个'user_id,book_id'记录只能在原始集合中出现一次。

#1


2  

Using a regular find you cannot get back all user_id fields who own all the book_id's because you normalized your collection (flattened it).

使用常规查找,您无法获取拥有所有book_id的所有user_id字段,因为您对集合进行了规范化(将其展平)。

You can do it, if you use aggregation framework:

如果使用聚合框架,则可以执行此操作:

db.collection.aggregate([
    {
        $match: {
            book_id: {
                $in: ["507f191e810c19729de860ea",
                      "507f191e810c19729de345ez",
                      "507f191e810c19729de860efr" ]
            }
        }
    },
    {
        $group: {
            _id: "$user_id",
            count: { $sum: 1 }
        }
    },
    {
        $match: {
            count: 3
        }
    },
    {
        $group: {
            _id: null,
            users: { $addToSet: "$_id" }
        }
    }
]);

What this does is filters through the pipeline only for documents which match one of the three book_id values, then it groups by user_id and counts how many matches that user got. If they got three they pass to the next pipeline operation which groups them into an array of user_ids. This solution assumes that each 'user_id,book_id' record can only appear once in the original collection.

这样做只是为了匹配三个book_id值之一的文档过滤管道,然后按user_id分组并计算用户获得的匹配数。如果他们有三个,他们将传递给下一个管道操作,该操作将它们分组为user_id数组。此解决方案假定每个'user_id,book_id'记录只能在原始集合中出现一次。