0

I haven't done much work with mongo so coming from mysql it is a bit of a challenge. What I want to do is get the data for the users in my friends array ie: their name, email etc. This is what I have below. When I hit a certain route I send my ID to the api endpoint. I then need to get the friend ID's from the array and get their relevant information.

Record in the database

{
    "_id": {
        "$oid": "5f1b22a427e4624711bdef0e"
    },
    "friends": [{
        "$oid": "5f206e15e9b66391246788d6"
    }, {
        "$oid": "5f2456777656525890dd9c21"
    }],
    "name": "Joe Smith",
    "email": "[email protected]",
    "mobile": "1233455467889",
}

Controller

exports.getAddedContacts = async (req, res) => {
  const userId = req.params.uid;
  let friends;

  try {
    friends = await User.find({ _id: userId });
  } catch (err) {
    res
      .status(500)
      .json({ error: "Something went wrong, could not get contacts" });
  }

  if (!friends || friends.length === 0) {
    res.status(404).json({ error: "No contacts found..." });
  }

  res.status(200).json({ friends: friends });
};

1 Answer 1

1

You could use an aggregation where you would use $match as the first stage in you pipeline just so you isolate only one user and then use populate to get your friends documents.

here is an example:

db.classes.insert( [
   { _id: 1, title: "Reading is ...", enrollmentlist: [ "giraffe2", "pandabear", "artie" ], days: ["M", "W", "F"] },
   { _id: 2, title: "But Writing ...", enrollmentlist: [ "giraffe1", "artie" ], days: ["T", "F"] }
])
db.members.insert( [
   { _id: 1, name: "artie", joined: new Date("2016-05-01"), status: "A" },
   { _id: 2, name: "giraffe", joined: new Date("2017-05-01"), status: "D" },
   { _id: 3, name: "giraffe1", joined: new Date("2017-10-01"), status: "A" },
   { _id: 4, name: "panda", joined: new Date("2018-10-11"), status: "A" },
   { _id: 5, name: "pandabear", joined: new Date("2018-12-01"), status: "A" },
   { _id: 6, name: "giraffe2", joined: new Date("2018-12-01"), status: "D" }
])
db.classes.aggregate([
   {
      $match: {
        _id: 1
      }
   }
   {
      $lookup:
         {
            from: "members",
            localField: "enrollmentlist",
            foreignField: "name",
            as: "enrollee_info"
        }
   }
])

You can find out more about this in official documentation

Just watch out for the result, aggregation always returns a list you so you have to do something like const [user] = await result.toArray()

Since you use mongoose you could also try using populate (check out docs) on your model like so:


const author = new Person({
  _id: new mongoose.Types.ObjectId(),
  name: 'Ian Fleming',
  age: 50
});

author.save(function (err) {
  if (err) return handleError(err);

  const story1 = new Story({
    title: 'Casino Royale',
    author: author._id    // assign the _id from the person
  });

  story1.save(function (err) {
    if (err) return handleError(err);
    // that's it!
  });
});

Story.
  findOne({ title: 'Casino Royale' }).
  populate('author').
  exec(function (err, story) {
    if (err) return handleError(err);
    console.log('The author is %s', story.author.name);
    // prints "The author is Ian Fleming"
  });

NOTE: I noticed in your question that you are storing what should be an array of ObjectID-s as an array of objects containing a single field string representing an ObjectID, this has to be changed if you want populate or lookup to work.

Sign up to request clarification or add additional context in comments.

4 Comments

I am a bit confused here, it looks like your examples are using 2 different documents, one for members and one for classes. I have only one which is Users and have a friends array in the user document.
I see no problem in referencing the same collection in regards of the $lookup solution, in regrd to the second one, the model User should contain self reference in the friends field, this is doable but is a topic for another question, one which i know is already answered on SO, i'll see if I can dig it up later in the day
I actually got it to work using findOne and populate, thanks!
Happy to hear it helped you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.