Rafael Rafael - 6 months ago 16
Node.js Question

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 :)


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):