TestWell TestWell - 1 month ago 8
Javascript Question

How do I search one array for items from another array in MongoDB?

I have a

users
table that has the following data structure:

[{
userID: 0,
username: 'test0',
petsForSale: [
{ type: 'fish' },
{ type: 'cats' }
],
seekingPets: [
{ type: 'dogs' },
{ type: 'birds' }
]
},
{
userID: 1,
username: 'test1',
petsForSale: [
{ type: 'guinea pigs' },
{ type: 'dogs' },
{ type: 'hamsters' }
],
seekingPets: [
{ type: 'ferrets' }
]
}]


I'm trying to execute a
GET
that returns matched users based on
petsForSale
and
seekingPets
. For example, if a user is selling
dogs
, they will show up on the list of matched results for any user with
dogs
in
seekingPets
. I'm very close, here's my router code so far:

router.get('/:id/findmatches', function(req, res) {
var db = req.db;
var collection = db.get('users');
var uid = req.params.id;

//var seeking_pets = collection.find({ userID: uid }, { seekingPets: 1 });
//var seeking_pets = collection.find({ userID: uid }, { seekingPets: { type: 1 }});
var seeking_pets = [ 'dogs', 'birds' ]; // *Hard-coded is the only way I can get it to work

collection.find({ petsForSale: { $elemMatch: { type: { $in: seeking_pets }}}}, function(e, docs) {
res.json(docs);
});
});


This code compiles and works just fine with
seeking_pets
hard-coded - visiting
/users/0/findmatches
returns user
test1
as expected. I'm stuck extracting the list of
seekingPets
from the
userID
in the request and searching through it in
collection.find
. The two commented lines are what I've tried without success. I've also tried converting the
collection
to an
array
.

Answer

As find is an async method, you must implement a callback in order to get the values returned from the database. Also notice that your hardcoded values are strings, but the seekingPets array is of objects.

Try this:

router.get('/:id/findmatches', function(req, res) {
  var db = req.db;
  var collection = db.get('users');
  var uid = req.params.id;

  collection.findOne({ userID: uid }, function(err, user)
      var seeking_pets = [].
      for (var i = 0; i < user.seekingPets.length; i++) {
        seeking_pets.push(user.seekingPets[i].type);
      }

      collection.find({ petsForSale: { $elemMatch: { type: { $in: seeking_pets }}}}, function(e, docs) {
          res.json(docs);
      });

  });
});

Notice that I use findOne in order to get an object instead of an array, and from this object I get the seekingPets array. Of course you can improve this code, eliminate some dispensable variables like seeking_pets and handle the database error if the id is not found.

Comments