0

I have a User collection with schema

{
     name: String, 
     books: [
         id: { type: Schema.Types.ObjectId, ref: 'Book' } ,
         name: String
     ]


}

Is it possible to get an array of book ids instead of object?

something like:

["53eb797a63ff0e8229b4aca1", "53eb797a63ff0e8229b4aca2", "53eb797a63ff0e8229b4aca3"]

Or

{ids: ["53eb797a63ff0e8229b4aca1", "53eb797a63ff0e8229b4aca2", "53eb797a63ff0e8229b4aca3"]}

and not

{
    _id: ObjectId("53eb79d863ff0e8229b97448"),
    books:[
        {"id" : ObjectId("53eb797a63ff0e8229b4aca1") }, 
        { "id" : ObjectId("53eb797a63ff0e8229b4acac") }, 
        { "id" : ObjectId("53eb797a63ff0e8229b4acad") }
    ]
}

Currently I am doing

User.findOne({}, {"books.id":1} ,function(err, result){
    var bookIds = [];
    result.books.forEach(function(book){
        bookIds.push(book.id);
    });

});

Is there any better way?

2
  • Your example is obviously broken. Commented Aug 18, 2014 at 16:25
  • This is not the exact use case. I just made it up to explain the problem easily :) Commented Aug 18, 2014 at 16:27

1 Answer 1

1

It could be easily done with Aggregation Pipeline, using $unwind and $group.

db.users.aggregate({
  $unwind: '$books'
}, {
  $group: {
    _id: 'books',
    ids: { $addToSet: '$books.id' }
  }
})

the same operation using mongoose Model.aggregate() method:

User.aggregate().unwind('$books').group(
  _id: 'books',
  ids: { $addToSet: '$books.id' }
}).exec(function(err, res) {
  // use res[0].ids
})

Note that books here is not a mongoose document, but a plain js object.


You can also add $match to select some part of users collection to run this aggregation query on.

For example, you may select only one particular user:

User.aggregate().match({
  _id: uid
}).unwind('$books').group(
  _id: 'books',
  ids: { $addToSet: '$books.id' }
}).exec(function(err, res) {
  // use res[0].ids
})

But if you're not interested in aggregating books from different users into single array, it's best to do it without using $group and $unwind:

User.aggregate().match({
  _id: uid
}).project({
  _id: 0,
  ids: '$books.id'
}).exec(function(err, users) {
  // use users[0].ids
})
Sign up to request clarification or add additional context in comments.

Comments

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.