1

I have the following Schema:

const userSchema = new Schema({
  local: {
    email: {type: String, unique: true, lowercase: true, trim: true, required: true},
    password: {type: String, required: true},
  },
  Items: [{
    name: {type: String, trim: true},
    createdAt: {type: Date, default: Date.now, select: false}
  }]
});

How do I query 'Items' (which contains array of objects) based on a specific _id that I will receive from the url parameter?

I have many different variations, including one shown below, but they all seem to return the Items array containing all objects, instead of just a single object matching the id?

User.findById(req.user.id, {}, {"Items._id": req.params.id}, (err, result) => { ... }
7
  • Use projection. Something like User.findOne({_id:req.user.id, "Items._id": req.params.id},{}, {"Items.$": 1}, (err, result) => { ... } Commented Mar 22, 2017 at 23:00
  • Still returns all of the Items instead of just a single one Commented Mar 22, 2017 at 23:43
  • May be I have the incorrect mongoose query. You can verify it running it in mongo shell. db.users.findOne({_id:req.user.id, "Items._id": req.params.id},{"Items.$": 1}). It will return one item value. I'll try to find the right mongoose query. Commented Mar 23, 2017 at 0:35
  • Yeah it does work in the mongo shell, should i use it in mongoose? or is there more efficient way to write it? Thanks Commented Mar 23, 2017 at 0:45
  • Np. Yeah if you know how to convert to mongoose. I believe this is the right query in mongoose. User.findOne({_id:req.user.id, "Items._id": req.params.id},{"Items.$": 1}, (err, result) => { ... } Commented Mar 23, 2017 at 0:48

2 Answers 2

2

You will have to use $projection to access element from embedded array. The query part finds the matching array element and replaces the placeholder $ with the array index of the matching element and projection part with $ will now use the placeholder value to project the array element as a response.

Mongo Shell Variant : db.users.findOne({_id:req.user.id, "Items._id": req.params.id},{"Items.$": 1})

Mongoose Variant: User.findOne({_id:req.user.id, "Items._id": req.params.id},{"Items.$": 1}, (err, result) => { ... }

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

6 Comments

Can you show me your query ? Mixing of exclusion and inclusion paths are not allowed in projection with the exception of _id field.
It's the same as what you provided, just the second object contains "_id":0 in front of "Items.$":1 which works fine, but how would I modify this overall query to get rid of the createdAt property from the result? I suppose I can call lean() on findOne to turn it into a regular object and then use delete user.Items[0].createdAt, but any way of doing it on the database side?
Nope, you can't like I said. You can't have both inclusion("Items.$": 1) and exclusion path ("Items.createdAt": 0) in the same projection. You have to take care of that on the mongoose side. More here docs.mongodb.com/v3.2/tutorial/…
Sorry I'm new to mongo and mongooose, would calling lean() on findOne and using delete user.Items[0].createdAt be an efficient way to solve this problem? Or is there a more efficient way to accomplish this?
I'm no expert in mongoose but looks like lean is what you need if you are concerned with performance which I personally think is not a issue here at all. This gives more info about lean stackoverflow.com/questions/7503450/… & stackoverflow.com/questions/15097375/… . I hope this calms you a little bit.
|
0

What you're trying to do is query for a subdocument. Check out http://mongoosejs.com/docs/subdocs.html

You can do something like:

User.findById(req.user.id, (err, user) => {
 let item = user.Items.id(req.params.id);
});

5 Comments

I'm looking for a way to do it on the database side, rather then app level
And I'm not using a subdocument, I have a single schema, 'Items' is just a name, just like 'local'
@linasmnew Yes, those are subdocuments - that's why they have _id. Unless you specify that you do not want an ID, it will be there. All objects in Mongo are documents.
Thanks didn't know that, what does the 'id' in user.Items.id refer to? because when i query the database inside the terminal there's only _id
DocumentArrays have a special id method for looking up a document by its _id. mongoosejs.com/docs/subdocs.html

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.