Exclude field in array of subdocument in mongodb - node.js

I have two document
image document:
{_id:123,user:{user_sub_docuemnt},thumb:'dqwdqwdqwdw'}
post document:
{_id:444,
user:{user_sub_document},
attach:[{_id:123,
user:{user_sub_docuemnt},
thumb:'dqwdqwdqwdw'}
]
}
the user_sub_document contain password field, so I need to exclude that field.
This is what i have so far:
Post.aggregate([
{$match: {'user._id': {$in:idArr}}},
{$project:{content:1,attach:1,pub_date:1,'user.avatar':1}},
],function(err,posts){
if(err){
throw err
}else{
res.send(posts)
}
})
this will only limit user in Post level, there is another user_sub_document in attach array,so I tried this
{$project:{content:1,attach:1,'attach.user':0,pub_date:1,'user.avatar':1}},
this will give me an error The top-level _id field is the only field currently supported for exclusion
please help me with this!

You can achieve this with a simple find() statement:
Post.find({"user._id":{$in:idArr}},
{"content":1,
"user.avatar":1,
"pub_date":1,
"attach.user.avatar":1})
In case you choose to aggregate for some reason, You could modify your aggregation pipeline as below:
$match the records with specific user Ids.
$project only the required fields.
code:
Post.aggregate([
{$match:{"user._id":{$in:idArr}}},
{$project:{"user.avatar":1,
"attach.user.avatar":1,
"pub_date":1,
"content":1}}],function(err,resp){
// handle response
})

Related

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"
]
}
});

Node.js/Express: mongoose/mongoDB update document with req.body but avoid updating _id field?

I am currently trying to update a document based on some _id value. If found, I want to update evreything with req.body, except setting a new _id (I want to avoid, that client can update their _id). So how can I do this? Would I update all fields manually and exclude _id field?
Currently I am doing this:
exports.updateDemoStatus = function(req, res) {
Status.findOneAndUpdate({Demonstrator: req.params.demo_id}, req.body, {new: true}, function(err, status) {
if (err)
console.log(status);
res.json(status);
});
};
Updating a document won't change it's _id field since it's unique and related to that specific document.
Please refer to the documentation.
As suggested on the Mongoose official docs, if you need full-fledged validation, use the traditional approach of first retrieving the document.

Query/Find MongoDB documents with series of multiple conditions

I have a User schema with basic fields which include interests, location co-ordinates
I need to perform POST request with a specific UserId to get the results
app.post('api/users/search/:id',function(err,docs)
{ //find all the documents whose search is enabled.
//on documents returned in above find the documents who have atleast 3 common interests(req.body.interests) with the user with ':id'
// -----OR-----
//find the documents who stay within 'req.body.distance' compared to location of user with':id'
//Something like this
return User
.find({isBuddyEnabled:true}),
.find({"interests":{"$all":req.body.interests}}),
.find({"_id":req.params.id},geoLib.distance([[req.body.gcordinates],[]))
});
Basically i need to perform find inside find or Query inside query..
As per your comments in the code you want to use multiple conditions in your find query such that either one of those condition is satisfied and returns the result based on it. You can use $or and $and to achieve it. A sample code with conditions similar to yours is given below.
find({
$or:[
{ isBuddyEnabled:true },
{ "interests": { "$all":req.body.interests }},
{ $and:[
{ "_id":req.params.id },
{ geoLib.distance...rest_of_the_condition }
]
}
]
});

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" ,...} }

Resources