I want to query a user by id, and then bring only the the foods that match to a type, how can i do this?
var type = 'fish';
var id = '597a348286ffe50d882a3033';
User.findById(id, { 'food.type': type }, 'food', function(err, model) {
if (err) {
console.log(err);
}
if (!model) {
console.log('no model');
}
if (model) {
console.log(model);
}
});
I would use aggregate combined with $filter:
User.aggregate([{
$match: { '_id': ObjectId('597a348286ffe50d882a3033') }
}, {
$project:
{
food: {
$filter: {
input: '$food',
as: 'food',
cond: {
$eq: ['$$food.type', type]
}
}
}
}
}])
This will first select the document matching the given Id then will return the list of foods of the given type.
Just filter the food after you get the user.
User.findById(id, function (err, user) {
if (err) {
console.log(err);
}
if (!user) {
console.log('no user');
}
if (user) {
var food = user.food.filter(function (food) { return food.type === type; });
}
});
You can create an obj something like this
var obj =
{
_id:'597a348286ffe50d882a3033',
'food.type' : 'fish'
}
and then pass this function as filter
User.find(obj, function(err, model) {
if (err) {
console.log(err);
}
// find will return empty array and not null
if (!model.length) {
console.log('no model');
}
if (model) {
console.log(model);
}
});
If you are finding the object using mongo _id field you don't have to use additional filter function after query execution you directly specify in the search query
Model.findOne({_id: '123jasdoisd123', 'food.type': type },
function(err, food){
if(err) return err;
if(!food){
// send the empty data
return []
}
return food;
}
)
Related
var query = { "to": req.params.id };
var mysort = { receivedDate: 1 };
Message.find(query, (err, doc) => {
if (!err) {
res.json(doc);
} else {
res.json(err);
}
});
The syntax is like the following:
db.collecttionName.find().sort({date:1});
But instead of date, you can pass in other criteria.
I've route that's suppose to filter my files based on 3 inputs - and that works.
app.get("/api/getFiles", (req, res) => {
let grade = req.query.grade;
let study = req.query.study;
let subject = req.query.subject;
User.find(
{ files: { $elemMatch: { study: study, subject: subject, grade: grade } } },
(err, doc) => {
if (err) res.status(400).send(err);
res.send(doc);
}
);
});
However, these inputs are not dependent on one another.
E.G if grade = 5 function should return files that match specific grade regardless of their study or subject.
Is there any default value in $elemMatch that will, in this case, get all files regardless of their study or subject ?
There is no default value for $elemMatch, you have to write the custom conditions in the code only
app.get("/api/getFiles", (req, res) => {
let grade = req.query.grade;
let study = req.query.study;
let subject = req.query.subject;
if grade == 5:{
User.find(
{ files: { $elemMatch: {grade: 5 } } },
(err, doc) => {
if (err) res.status(400).send(err);
res.send(doc);
}
);}
else: {
User.find(
{ files: { $elemMatch: { study: study, subject: subject, grade: grade } } },
(err, doc) => {
if (err) res.status(400).send(err);
res.send(doc);
}
);}
});
I am using MongoDB and I am trying to grab a specific object based on its _id and all of the sibling elements as well. For example my array looks like this:
"blogs": [
{
"body": "default valuee",
"header": "another first",
"_id": "1234"
},
{
"body": "second default value",
"header": "second",
"_id": "5678"
}
]
And I am trying to grab the values that are beside the _id of 1234 (so the body,header and _id fields of just that object). I have tried a few Mongo queries but with no such luck. Any help would be great, cheers
My function is :
module.exports = function findBlog(db, id, callback){
var UserCollection = db.collection('users') //connect to business collection
UserCollection.findOne({ 'blogs._id': id }, {body: 1, header: 1, _id: { $elemMatch: { _id: id}}},function (err, user) {
if (err){
return callback({response: "3"})
}else if(!user){
return callback({response: "4"})
}else {
return callback({response: "2",data:user.blogs})
}
});
}
You should use something like this,
If you want all fields from blogs and user you can directly use,
UserCollection.find({ 'blogs._id': id }, { blogs:{ $elemMatch:{ _id: id }}},function (err, user) {
if (err){
return callback({response: "3"})
}else if(!user){
return callback({response: "4"})
}else {
return callback({response: "2",data:user.blogs})
}
});
}
If you need specific fields:
First parameter you will add condition: { 'blogs._id': id }
Second parameter you will add fields required: { "blogs.body": 1,"blogs.header": 1 }
UserCollection.findOne({ 'blogs._id': id }, { "blogs.body": 1,"blogs.header": 1 },function (err, user) {
if (err){
return callback({response: "3"})
}else if(!user){
return callback({response: "4"})
}else {
return callback({response: "2",data:user})
}
});
}
As I stated in a comment on the OP's question, the best way to to work this out is to create a Blog collection. You can then query this collection directly instead of querying the User collection.
You can still have the blogs property in the User model by linking a blog to a user. (see the Mongoose documentation on populate)
I am trying to perform search on my list in node js and my code below is subjected to that,
exports.searchlistbyfirstname = function (req, res) {
var params = req.params;
var record= db.collection('profile');
record.find( { $text: { $search: params.id} }, (err, result) => {
if (err){ return console.log(err)
}
if(result){
response = {status:'success',data:result};
} else{
response = {status:'fail'};
}
res.send(response);
});
};
I am trying to search firstname and I am sure I got wrong.
can anyone please help me
You can try this query to get your firstname
record.find({
firstname: {
$regex: params.id
}
}, (err, result) => {
if (err) {
return console.log(err)
}
if (result) {
response = {
status: 'success',
data: result
};
} else {
response = {
status: 'fail'
};
}
res.send(response);
});
To perform text search ensure first you have created text index for search field.
like:
db.collection('profile').createIndex( { firstName: "text" } );
then you can perform text search on that filed(s).
// params.id should be like "shaishab"
// but better to use req.query.firstName instead of req.params.id
// and you should change your route for that
record.find({$text: {$search: params.id}}, (err, result) => {
if (err) {
console.log(err)
return res.status(400).send({status: 'fail', error: err});
}
if (result) {
response = {status: 'success', data: result};
} else {
response = {status: 'fail'};
}
res.send(response);
});
Or without create text index you can search firstName by using $regex operator
record.find({firstName: { $regex: req.params.id, $options: 'i' } }, (err, result) => {
if (err) {
console.log(err)
return res.status(400).send({status: 'fail', error: err});
}
if (result) {
response = {status: 'success', data: result};
} else {
response = {status: 'fail'};
}
res.send(response);
});
I cannot get a result with aggregation option parameter. Here is my aggregation:-
var emails = getAllEmails();
var listMatchColl = 'list_matches_' + insertedId;
SurveyDL.aggregate([
{ $match: { email: { $in: emails } } },
{ $out: listMatchColl }
], {
allowDiskUse: true
}).exec(function(err, data) {
if (err) return console.log('err', err);
console.log('data',data);
});
}
When i execute above code it thrown and error i.e,
Error: Arguments must be aggregate pipeline operators
at Aggregate.append (/home/vivek/nrich/node_modules/mongoose/lib/aggregate.js:89:11)
at new Aggregate (/home/vivek/nrich/node_modules/mongoose/lib/aggregate.js:48:17)
I have also use the alternative way but it still throw same error. Alternative way :-
var emails = getAllEmails();
var listMatchColl = 'list_matches_' + insertedId;
SurveyDL.aggregate([
{ $match: { email: { $in: emails } } },
{ $out: listMatchColl }
], {
allowDiskUse: true
},function(err, data) {
if (err) return console.log('err', err);
console.log('data',data);
});
Try setting the allowDiskUse() option for the aggregation query:
var emails = getAllEmails();
var listMatchColl = 'list_matches_' + insertedId;
SurveyDL.aggregate([
{ '$match': { 'email': { '$in': emails } } },
{ '$out': listMatchColl }
]).allowDiskUse(true)
.exec(function(err, data) {
if (err) return console.log('err', err);
console.log('data',data);
});
or using the fluent API:
SurveyDL.aggregate()
.match({ 'email': { '$in': emails } })
.append({ '$out': listMatchColl })
.allowDiskUse(true)
.exec(function(err, data) {
if (err) return console.log('err', err);
console.log('data',data);
});
You might be running over the 16MB aggregation size limit and the allowDiskUse() option is not sufficient if your data will be > 16MB since it just lets you use sort when your data is large. Consider using the aggregation cursor form to access your aggregated documents:
var cursor = SurveyDL.aggregate([
{ $match: { email: { $in: emails } } }
]).cursor({ batchSize: 1000 }).exec();
cursor.each(function(error, doc) {
// use doc
});
var emails must be Array.
listMatchColl must be String.
{ $out: 'listMatchColl' }
and if you use $out, you can`t see result your aggregation.
Your result in new collection 'listMatchColl'.