How to set default value with $elemMatch in Mongoose and Nddejs - node.js

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

Related

How to Sort the MongoDB data using NodeJS

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.

Adding JSON object to redis that can be queried - nodejs

Originally I was trying to add the documents returned from User.find({}) into the redis cache as a sorted set so that I can do pagination. like so: client.zadd("directory", documents_id, docsString, (err, reply) => {
I'm starting to wonder if I need to use hmset since I'm dealing with multiple items in JSON object, but I'm not sure how to query if that's the case. I'm looking for the best solution that will later allow me to paginate the data and also have a keyword that returns matching values in fields (if possible to any extent with redis)
app.get("/api/users", (req, res, next) => {
var searchKey = new RegExp(req.query.usernameSearch, "i");
console.log("CURRENT PAGE IS " + req.query.currentPage);
client.zrange("directory", 0, -1, (err, reply) => {
console.log("reply");
console.log(reply);
console.log(err);
if (err) {
res.status(401).json({
message: "Directory Cache Error!"
});
return;
} else if (reply) {
console.log("GRABBING FROM CACHE");
let packageReply = JSON.parse(reply);
console.log("packageReply");
console.log(packageReply);
let totatArtists = packageReply.length;
res.status(200).json({
message: "Grabbed from cache",
posts: packageReply,
maxPosts: totatArtists
});
} else {
console.log("GRABBING FROM DB");
User.countDocuments({
$and: [{ username: searchKey }, { role: "Seller" }]
}).then(docs => {
let totalPosts = docs;
let postPerPage = 20;
User.find({
$and: [{ username: searchKey }, { role: "Seller" }]
})
.select("_id username")
.skip(postPerPage * (currentPage - 1))
.limit(postPerPage)
.then(documents => {
let docsString = JSON.stringify(documents);
client.zadd(
"directory",
documents_id,
docsString,
(err, reply) => {
client.expire("directory", 3600);
res.status(200).json({
message: "Users retrieved successfully!",
posts: documents
});
}
);
});
});
}
});
sample output
[{ _id: 5e34482ce04d7c0ca4725f92, username: 'bob' },
{ _id: 5e344842e04d7c0ca4725f93, username: 'joe' },
{ _id: 5e383e5dace65e4774e646e1, username: 'bill' },
{ _id: 5e383e63ace65e4774e646e2, username: 'sue' }]
The client.zadd("directory", ... function has parameters:
The first is the key of the Z set
The second is score (number)
The third is new value
Assuming document ID is the score you want to use to later retrieve, you should do:
client.zadd("directory", documents._id, docsString, ...

mongoose find one and update function

Suppose that we have a shopping cart in the site, we have specified number of a good in database. Whenever the user wants to validate his/her cart and finalize it, I want to subtract the number of goods that the user purchased from total count of the product. How can I do that?
router.post('/done', (req, res) => {
// substract from the count
for (var i = 0; i < req.body.cart.length; i++){
Product.findOne({_id: req.body.cart[i]._id}).exec((err, result) => {
result.count = result.count - req.body.cart[i].count;
// update the value of result.count and save it on database
})
}
})
You just need to save, and also check for errors.
router.post('/done', (req, res) => {
// substract from the count
for (var i = 0; i < req.body.cart.length; i++){
Product.findOne({_id: req.body.cart[i]._id}).exec((err, result) => {
if(result)
{
result.count = result.count - req.body.cart[i].count;
result.save((err) => {
if (err) // do something
});
}
//If you don't find the product for some reason, do something
})
}
})
You can use mongoose's findOneAndUpdate() and $inc reference operator with a negative value to decrement the count.
Docs
The following update() operation uses the $inc operator to decrease the quantity field by 2 (i.e. increase by -2) and increase the "metrics.orders" field by 1:
db.products.update(
{ sku: "abc123" },
{ $inc: { quantity: -2, "metrics.orders": 1 } }
)
Making those changes
'use strict';
router.post('/done', (req, res) => {
let {cart} = req.body;
if (!Array.isArray(cart) || cart.length === 0) {
return res.status(400).send({
msg: 'Empty cart'
});
}
let updates = cart.map(item => {
return Product.findOneAndUpdate({
_id: item._id
}, {
$inc: {
count: -1 * item.count
}
}, {
upsert: false
});
});
Promise.all(updates).then(() => {
return res.status(200).send({
msg: 'inventory updated'
});
}).catch(err => {
console.log('err', err.stack);
return res.status(500).send({
msg: 'inventory update failed!'
});
});
});

mongoose FindbyId and where array match to a string

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

How to perform search in Node.js MongoDB

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

Resources