How to join query in mongodb?

2019-01-08 14:01发布

问题:

I have user document collection like this:

User {
   id:"001"
   name:"John",
   age:30,
   friends:["userId1","userId2","userId3"....]
}

A user has many friends, I have the following query in SQL:

select * from user where in (select friends from user where id=?) order by age

I would like to have something similar in MongoDB.

回答1:

You can't do what you want in just one query. You would have to first retrieve the list of friend user ids, then pass those ids to the second query to retrieve the documents and sort them by age.

var user = db.user.findOne({"id" : "001"}, {"friends": 1})
db.user.find( {"id" : {$in : user.friends }}).sort("age" : 1);


回答2:

To have everything with just one query using the $lookup feature of the aggregation framework, try this :

db.User.aggregate(
    [
        // First step is to extract the "friends" field to work with the values
        {
            $unwind: "$friends"
        },
        // Lookup all the linked friends from the User collection
        {
            $lookup:
            {
                from: "User",
                localField: "friends",
                foreignField: "_id",
                as: "friendsData"
            }
        },
        // Sort the results by age
        {
            $sort: { 'friendsData.age': 1 }
        },
        // Get the results into a single array
        {
            $unwind: "$friendsData"
        },
        // Group the friends by user id
        {
            $group:
            {
                _id: "$_id",
                friends: { $push: "$friends" },
                friendsData: { $push: "$friendsData" }
            }
        }
    ]
)

Let's say the content of your User collection is the following:

{
    "_id" : ObjectId("573b09e6322304d5e7c6256e"),
    "name" : "John",
    "age" : 30,
    "friends" : [
        "userId1",
        "userId2",
        "userId3"
    ]
}
{ "_id" : "userId1", "name" : "Derek", "age" : 34 }
{ "_id" : "userId2", "name" : "Homer", "age" : 44 }
{ "_id" : "userId3", "name" : "Bobby", "age" : 12 }

The result of the query will be:

{
    "_id" : ObjectId("573b09e6322304d5e7c6256e"),
    "friends" : [
        "userId3",
        "userId1",
        "userId2"
    ],
    "friendsData" : [
        {
            "_id" : "userId3",
            "name" : "Bobby",
            "age" : 12
        },
        {
            "_id" : "userId1",
            "name" : "Derek",
            "age" : 34
        },
        {
            "_id" : "userId2",
            "name" : "Homer",
            "age" : 44
        }
    ]
}


回答3:

https://docs.mongodb.org/manual/reference/operator/aggregation/lookup/

This is the doc for join query in mongodb , this is new feature from version 3.2.

So this will be helpful.



回答4:

MongoDB doesn't have joins, but in your case you can do:

db.coll.find({friends: userId}).sort({age: -1})


回答5:

Looks like nobody talked about this option of using Pivot in addtion to MapReduce. There is a good article that could be your answer here http://cookbook.mongodb.org/patterns/pivot/ Hope this will help you in your projects



回答6:

one kind of join a query in mongoDB, is ask at one collection for id that match , put ids in a list (idlist) , and do find using on other (or same) collection with $in : idlist

u = db.friends.find({"friends": ? }).toArray()
idlist= []
u.forEach(function(myDoc) { idlist.push(myDoc.id ); } )
db.friends.find({"id": {$in : idlist} } )


回答7:

You can use playOrm to do what you want in one Query(with S-SQL Scalable SQL).



回答8:

var p = db.sample1.find().limit(2) , 
    h = [];
for (var i = 0; i < p.length(); i++) 
{
  h.push(p[i]['name']);
}
db.sample2.find( { 'doc_name': { $in : h } } ); 

it works for me.



回答9:

You can do it in one go using mongo-join-query. Here is how it would look like:

const joinQuery = require("mongo-join-query");

joinQuery(
    mongoose.models.User,
    {
        find: {},
        populate: ["friends"],
        sort: { age: 1 },
    },
    (err, res) => (err ? console.log("Error:", err) : console.log("Success:", res.results))
);

The result will have your users ordered by age and all of the friends objects embedded.

How does it work?

Behind the scenes mongo-join-query will use your Mongoose schema to determine which models to join and will create an aggregation pipeline that will perform the join and the query.



回答10:

Only populate array friends.

User.findOne({ _id: "userId"})
.populate('friends')
.exec((err, user) => {
    //do something
});

Result is same like this:

{
    "_id" : "userId",
    "name" : "John",
    "age" : 30,
    "friends" : [
        { "_id" : "userId1", "name" : "Derek", "age" : 34 }
        { "_id" : "userId2", "name" : "Homer", "age" : 44 }
        { "_id" : "userId3", "name" : "Bobby", "age" : 12 }
    ]
}

Same this: Mongoose - using Populate on an array of ObjectId