How to get only one item of a subdocument in mongoose? - node.js

ASchema={item:[BSchema]};
ASchema.findOne({item._id=xx})
It gets a array of BSchema, document.item is a array. how to get only one item which _id is xx?

You want the positional $ operator using query projection to just return your matched array element. For Mongoose you can do this:
ASchema.findOne({"item._id": itemId},"item.$",function(err,doc) {
console.log( doc );
});
Or paired in an object:
ASchema.findOne({"item._id": itemId},{ "item.$": 1 },function(err,doc) {
console.log( doc );
});
Mongoose supports the shorthand syntax with options like "-fieldname" for field removal which is the same as { "fieldname": 0 }. But you cannot mix inclusion and exclusion with the exception of the root _id field.
Therefore you must specify all of the fields you want to appear when using projection.
See also .select() in the mongoose documentation.

I think your syntax for the query is wrong. Try:
ASchema.findOne({'item._id': xx})
This link is helpful for more examples: http://mongoosejs.com/docs/queries.html

Related

Appending objects to array field using $push and $each returns null (Mongoose)

Background:
I have an array (A) of new objects that need to be added to an array field in Mongoose. if successful it should print to screen the newly updated object but it prints null. I checked the database and confirmed it also does not update at all. I followed the docs to use the $push and $each modifiers here:
https://www.mongodb.com/docs/manual/reference/operator/update/each/
Desired Behaviour:
I would like each object in (A) to be added to the Array field, not (A) itself. Upon success, it should print to screen the newly updated object.
Attempted Approach:
let identifier={customer:{external_id:'12345'}}
let array = [{value:30},{value:30}]
User.findOneAndUpdate(identifier,{$push:{points:{$each:array}}},{new:true})
.then((result)=>{
console.log(result)
})
Attempted Resolutions:
I tested if the issue was with the identifier parameter, but it works fine when the update parameter does not have $each (i.e. it pushes the whole array (A) into the array field)
I thought about using $addToSet like in the solution below, but as you can see in the sample code above, I want to push all objects even if they are not unique:
Mongoose - Push objects into nested array
use dot "." notation for embedded field
let filter={'customer.external_id':'12345'}
let array = [{value:30},{value:30}];
let update = { $push: { points: { $each: array } } };
User.findOneAndUpdate(filter,update,{new: true})
.then((result)=>{
console.log(result)
})
It turns out the IDs did not match. There was no issue with the code. Sorry guys.

mongodb get list of subdocuments that matched with list of values

my document schema goes like this
_id: kkj33h2kjkjh32jk34
events: [
{
_id: k234j3lk4k2j3h4j3j4
},
{
_id: k234j3lk4k2j3h4j3j4
},
{
_id: k234j3lk4k2j3h4j3j4
}
]
here is my query, I have a list of _ids of the subdocuments of events field and I need to get all the matched subdocuments as the response from the event field I have tried to use $in and many but failed can anyone suggest me how to do this
tried this
subarr=['fh576hgfu658uyg7h','k234j3lk4k2j3h4j3j4']
model.findOne({
clgid: req.query.clgid,
'events._id': {$in:subarr}
},{"events.$":1});
but the problem with the above code is that it is fetching the first matching subdocument. but I need all the matching subdocuments.
suggest me the right way to do this query so that I get all the matched subdocuments that match from array
The issue of your query matching only the first subdocument is the use of {"events.$":1} in your projection.
I'm not sure what you are actually intending to do.
{"events.$":1} will limit to the first (sub)document matching your query, as per the documentation of the $ operator.
Maybe you're trying only to get the _id of the subdocuments and then, please try the following:
subarr=['fh576hgfu658uyg7h','k234j3lk4k2j3h4j3j4']
model.findOne({
clgid: req.query.clgid,
'events._id': {$in:subarr}
},{"events._id":1});

Query find mongoose returns a document while its not $in array

I'm having issues with mongoose queries.
I am trying to check if a object with an Id is in an array of objects.
So my query is like
db.getCollection('adunits').find(
{_id: ObjectId("5bd9bc1ca4efae39d0b5a58e")},
{$in : ["5bf510156c154934150ef006","5bf5309e6c154934150f00a6","5bd9b874a4efae39d0b5a58d","5bf52a876c154934150efe4a"]}
)
As you can see, my ObjectId("5bd9...") IS NOT in the array. But my query returns the document with ObjectId("5bd9...").
Isn't the $in operator supposed to check if the _id in parameter is IN the array?
I wish it could return me a "0 fetched documents" because the id passed isn't in the array.
Thanks in advance
Your query is not right.
You can either find by id like so:
db.getCollection('adunits')
.find({_id: ObjectId("5bd9bc1ca4efae39d0b5a58e")})
to get a single document or use $in operator like so
db.getCollection('adunits')
.find({_id: { $in: ["5bf510156c154934150ef006","5bf5309e6c154934150f00a6",...]})
which will return documents which have one of the ids provided in the array.
You query condition finds adunits where _id = ObjectId("5bd9bc1ca4efae39d0b5a58e"), it returns the value that matches given condition. While $in operator should applied on a filed. Are you trying to achieve some thing like, find the documents that matches ids in given array.if yes , change your code to following. Visit mongodb official https://docs.mongodb.com/manual/reference/operator/query/in/.
db.getCollection('adunits').find(
{ "_id":
{ $in:
[ "5bf510156c154934150ef006",
"5bf5309e6c154934150f00a6",
"5bd9b874a4efae39d0b5a58d",
"5bf52a876c154934150efe4a"
]
}
});

need guidance on node.js multilingual presentation

I am new to node (v0.10) stack.
I am trying to achieve the following:
I have (hopefully) multilingual articles in the latest MongoDB such as:
_id
...more fields...
text: [
{lang: 'en', title: 'some title', body: 'body', slug: 'slug'},
....
]
Everytime I display an article in specific language I query as follows:
var query = Model.findOne({'text.slug': slug});
query.exec(function(err, doc){
async.each(doc.text, function(item, callback){
if (item.lang == articleLang) {
//populate the article to display
}
});
res.render('view', {post:articleToDisplay});
});
Slug is unique for each language!
The problem I have is that mongo will return the whole doc with all subdocs and not just the subdoc I searched for. Now I have to choose to iterate over all subdocs and display the appropriate one on client side or use async.each on the server to get the subdoc I need and only send to the views that one. I am doing it with async on the server. Is that OK? Also async iterates asynchronously but node still waits for the whole loop to finish and then renders the view. Am I missing anything thinking that the user is actually blocked until the async.each finishes? I am still trying to wrap my head around this asynchronous execution. Is there a way I can possibly improve how I manage this code? It seems to be quite standard procedure with subdocs!
Thanks in advance for all your help.
To achieve what you want, you need to make use of the aggregation pipeline. Using a simple findOne() would not be of help,
since you would then have to redact sub documents in your code rather than allowing mongodb to do it. find() and findOne() return the whole document when
a document matches the search criteria.
In the aggregation pipleline you could use the $unwind and $match operators to achieve this.
$unwind:
Deconstructs an array field from the input documents to output a
document for each element. Each output document is the input document
with the value of the array field replaced by the element.
First unwind the document based on the text values array.
$match:
Filters the documents to pass only the documents that match the
specified condition(s) to the next pipeline stage.
Then use the $match operator to match the appropriate documents.
db.Model.aggregate([
{$unwind:"$text"},
{$match:{"text.slug":slug,"text.lang":articleLang}}
])
Doing this would return you only one document with its text field containing only one object. such as: (Note that the text field in the output is not an array)
{ "_id" : ... ,.., "text" : { "slug" : "slug", "lang" : "en" ,...} }

Set field to empty for mongo object using mongoose

I have a document object that has an embedded sub-document.
To "clear" the sub-document, I try this:
obj.mysub = {};
obj.save();
This doesn't work, my object still has the contents of the mysub sub-document.
But this:
obj.mysub = undefined;
obj.save();
This does work, it removes my sub-document from the object.
My question is why doesn't the first version work? What is going on in Mongodb / Mongoose in the first example?
[edit] Why doesn't the empty object get saved in the first example above.
Mongoose sort of "protects" you from a lot of logic like you have presented in it's own internal resolution. So if you actually need to do this then do it at a lower level to the driver as in:
YourModel.update(
{ /*statement matching your document as a query */ },
{ "$unset": { "mysub": 1 } }
)
And per the normal MongoDB logic then this will work and remove that level in the document that was selected. See the $unset operator for more.

Resources