Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB relational query

I'm new with mongo and still trying to drift my head away from the mySQL methodology and dive it into mongo, so a few things are still blur on how i'm suppose to do and i was hopping you guys could shed me some light.

Let me explain the problem. I'm using nodeJS and the mongodb native.

Say i have a collection of users (i've used simpler _id just to illustrate, i know its an objectID, but consider just for the sake of the example)

{
     _id: 1,
     name: 'John',
     likes: ['2','3','4'] 
},
{
     _id: 2,
     name: 'Michelle'
     likes: ['1','4']
},
{
     name: 'Sabrina'
     _id: 3,
     likes: []
},
{
     name: 'Simone'
     _id: 4,
     likes: ['1','2', '3']
}

note that John liked Michell, Sabrina, and Simone, that Michelle liked John and Simone, Sabrina didn't like anyone, and Simone liked John, Michelle and Sabrina.

How do i run a query for John to find out who also liked him back based on his array of likes? I need something that would return Michelle if id = 1, or returns John and Michelle if id = 4. Only the ones that the id i'm fetching is in the other users like.

let me try to simplify.

I need to fetch John and go through all his likes and check id 2 likes me back? Yes id 3 likes me back? No

return [John];

or fetch Simone and go through all her likes and check id 1 likes me back? Yes id 2 likes me back? Yes id 3 likes me back? No

return [John, Michelle]

Any help would be appreciated :) thanks

like image 677
Rafael Avatar asked Apr 13 '13 02:04

Rafael


2 Answers

Here we go:

Something like this should do the trick using the mongodb-native driver in nodejs:

var people = db.collection("users");
people.findOne({name: "John"}, function(err, result)
  if(err) throw err; //..or however you want to handle an error.
  people.find({_id: {$in: result.likes}, likes:result._id}).toArray(function(err, others)
    {
    if(err) throw err; //...again, your call how to handle a potential error.
    //finds all people who are in likes array AND have Johns ID in their likes array.
    });
  });

Basically, first you retrieve the record for John. Next, you use his likes array to retrieve all users with matching id's :)

Note that this can be optimised slightly by opting to only retrieve the liked field for John, as in:

people.findOne({name: "John"}, {"likes": 1}, function(err, result)
  {
  //.....
  });

Also note that if the likes array is particularly massive, you may want to retrieve values one at a time rather than all at once using the .toArray() method, by instead using the cursor returned from find() and working with items one at a time, as in:

//....
var cursor = people.find({_id: {$in: result.likes}, likes:result._id});
cursor.each(function(err, item)
    {
    if(err) throw err; //...
    if(item != null)
    //do stuff with each person returned given likes array
    });
//....

I'm afraid I havnt tested the above, so apologies if I made any mistakes!

I find the manual for the mongo-native node.js driver to be invaluable; it covers most things pretty well (although some of the code seems a little "older" than other bits):

http://mongodb.github.io/node-mongodb-native/api-articles/nodekoarticle1.html

like image 95
jsdw Avatar answered Sep 29 '22 13:09

jsdw


It has to be done in two queries (since Mongo is non-relational). The fist query would be to get the person (I'm sure you've figured out how to do that). The second would answer who likes him/her back.

var userId = 1;
people.findOne({ _id: userId }, { likes: 1 }, function (err, person) {
    if (err)
        throw err; // <-- obviously handle the error better than this

    people.find({ _id: { $in: person.likes }, likes: userId }).toArray(
        function (err, likers) {
            //now you have your list of people who liked the user back
        }
    );
});
like image 40
Bret Copeland Avatar answered Sep 29 '22 13:09

Bret Copeland