I want to send request to a mongodb database.
For example I have this object:
{
id:"1",
requestType : {
"api1" : {count:12,firstTime:12},
"api2" : {count:6,firstTime:18}
}
}
after getting data by "id" I want to append another row to "requestType" for example "api3":{count:56,firstTime:11}.
my expected object is:
{
id:"1",
requestType : {
"api1" : {count:12,firstTime:12},
"api2" : {count:6,firstTime:18},
"api3":{count:56,firstTime:11}
}
}
currently I'm using this query by mongoose:
apiAttemptsModel.findOneAndUpdate(query, {
$set: {
requestType : {"api3":{count:56,firstTime:11}}
}
}, {upsert: true, new: true}, function (err, row) {
if (err) {
callback('err is ' + err)
} else {
callback(row);
}
});
But this code will exchange old requestType object with the new one.
Try this:
apiAttemptsModel.findOneAndUpdate(query, {
$set: {
"requestType.api3" : {count:56, firstTime:11}
}
}, {upsert: true, new: true}, function (err, row) {
if (err) {
callback('err is ' + err)
} else {
callback(row);
}
});
By the way, this is not the proper way to use callbacks.
callbacks in node are usually called with the following signature:
function(error, data) -
thus when calling callback(row); a user of this method might expect an error there, much like you did with the callback function on line 5.
The first argument is usually null when no error has occurred.
In addition, calling callback('err is ' + err) will only keep the error's message and discard its stack trace, because the error is "converted" to a string.
I'd convert your code to:
apiAttemptsModel.findOneAndUpdate(query, {
$set: {
"requestType.api3" : {count:56, firstTime:11}
}
}, {upsert: true, new: true}, function (err, row) {
if (err) {
callback(err)
} else {
callback(null, row);
}
});
Set upset to false. This will update the document, but will not create it if it does not already exist.
https://docs.mongodb.com/manual/reference/method/db.collection.update/
Related
I have a callback function that returns an object from the database. However, in my async.waterfall the function 'external' does not wait for the object to be fully loaded meaning it is undefined when passed in. This means my final error is TypeError: Cannot read property 'replace' of undefined. What am I doing wrong?
function loadModelInstance (name, callback) {
Model.findOne({ name: name }, function (_err, result) {
if (result) {
return callback(_err, result.content)
}
})
}
function generatedNow (modelInstance) {
generatedKeys = generatedKeys.concat(getAllMatches(generatedRegexp, modelInstance.replace(/(\n|\r)/g, '')));
}
async.waterfall(
[
function loadTemplate (wfaCallback) {
loadModelInstance(name, function (_err, modelInstance) {
wfaCallback(_err, modelInstance)
})
},
function external (modelInstance, wfaCallback) {
generatedNow(tracking, message, modelInstance, placeholders, function (err, updatedPlaceholders) {
})
},
],
function (err) {
// Node.js and JavaScript Rock!
}
);
Could you please provide more details. where are you calling "generateNow" function. i don't see function call for "generateNow".
Looks like you haven't used the parameter order properly. Below code should work.
async.waterfall(
[
function loadTemplate(wfaCallback) {
loadModelInstance(name, function(_err, modelInstance) {
wfaCallback(_err, modelInstance);
});
},
function external(err, modelInstance, wfaCallback) {
generatedNow(modelInstance, tracking, message, placeholders, function(
err,
updatedPlaceholders
) {});
}
],
function(err) {
// Node.js and JavaScript Rock!
}
);
This is my db schema
let couponId = Schema({
RestaurantId: { type: String },
RestaurantName: { type: String },
RestaurantLocation: { type: String },
AssignedTo: Schema.Types.Mixed,
CouponValue: { type: [String] }
});
I want to update the AssignedTo field with a value of array of objects with a dynamic key and a value. I am performing this query
CouponId.findOne({
"RestaurantId": resId
}, (err, restaurant) => {
value.push({
[userNumber]: restaurant.CouponValue[0]
});
console.log(value);
restaurant.update({
"RestaurantId": resId
}, {
$set: {
"AssignedTo": value
}
}, function(err) {
if (err) {
console.log(err);
} else {
console.log("updated");
}
});
});
The query, when executed, is giving the result of updated in console but its not getting updated in db. If this query is converted to MongoShell query and executed, it gives the result and collection is getting updated, where mongoShell query i am running is
db.couponids.update({"RestaurantId" : "1234"},{$set:{"AssignedTo":[{"1234":"2345"}]}});
Where am i going wrong?
restaurant is the output from the first collection and doesn't have any update function in it... So, You need to keep the same collection name from which you have done findOne
CouponId.update({
"RestaurantId": resId
}, {
$set: {
"AssignedTo": value
}
}, function(err) {
if (err) {
console.log(err);
} else {
console.log("updated");
}
});
I am trying to add two values in a mongoose function.
This the function im using:
Equipa.findOne({ '_id': req.params.equipaID }, function (error, equipa) {
if (error) {
return (error);
}
if (util.isNullOrUndefined(equipa)) {
return res.status(204).end()
}
console.log(equipa.distanciaTotal + "------" + req.body.distanciaPercorrida),
{ total : {$add[equipa.distanciaTotal,req.body.distanciaPercorrida]}},
console.log(total)
});
The values in equipa.distanciaTotal and req.body.distanciaPercorrida are correct, and so is the Equipa found by Equipa.findOne.
I think it will be fine updating the document, but I simply cannot add the two values.
You can use $inc to increment the existing value
Equipa.findOneAndUpdate(
{ '_id': req.params.equipaID },
{ '$inc': {
distanciaTotal: req.body.distanciaPercorrida }
}
)
You could either use $inc
Equipa.findOneAndUpdate(
{ '_id': req.params.equipaID },
{ $inc: { distanciaTotal: req.body.distanciaPercorrida } }
);
Or save the document after updating it
Equipa.findOne({ '_id': req.params.equipaID }, (err, equipa) => {
equipa.distanciaTotal += req.body.distanciaPercorrida;
equipa.save();
});
Im trying to write a function that will search for an object by ID and whether or not a value is contained in an embedded array within the object.
{
"_id" : ObjectId("569bea91c0e1fee4063527ac"),
"user" : ObjectId("568c65174fee132c36e199dd"),
"votes" : 9,
"image" : "./modules/deals/client/img/uploads/1546f914dba7e1732ea853cd70d79148.jpg",
"price" : "12.95",
"retailer" : "argos.co.uk",
"voters" : [{
"user" : ObjectId("568c65174fee132c36e199dd"),
},
{
"user" : ObjectId("568c65174fee132c36e199dd"),
},
{
"user" : ObjectId("568c65174fee132c36e199dd"),
}]
I would like to search by the _id and the voters.user.
I believe i need to finish this function correctly
exports.dealByIdAndVoter = function(req, res) {
Deal.count({
$where: function () {
}
},
function(err, dealByIdAndVoter) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
console.log(dealByIdAndVoter);
var data = {};
data.count = dealByIdAndVoter;
res.json(data);
}
});
};
If you do not need to use the $where function, you can construct the query with the $or operator in this manner:
Deal
.find({
$or: [
// Match by _id
{ _id: req.id },
// Match by any user in the 'voters' array with a matching 'user' field.
{ 'voters.$.user': req.id }
]
})
.count(function(err, count) {
// Handle error here
res.json(count);
});
I receive a POST argument that looks like this:
sort:
[
{ field: 'name', dir: 'asc', compare: '' },
{ field: 'org', dir: 'asc', compare: '' }
]
}
and I need to create a MongoDB query based on that, so it should look like:
db.collection("my_collection").find( ... ).sort({'name': 'asc', 'org': 'asc'}).toArray(...);
Anyways, keep in mind that more fields could be passed. Also, it could happen that none of those fields is passed, meaning that the query won't have .sort().
My question: How can I create dynamically a query with Node's MongoDB driver? Is there a query builder or something similar?
I've found that most cases are unique regarding passed data, so building query objects varies from project to project.
So first ideas was to create middleware for express (in my case), that would parse query arguments into objects that are valid for query.
mongo-native can use as chained options to cursor, as well as in object:
Chained:
items.find({ type: 'location' }).sort({ title: 1 }).limit(42).toArray(function(err, data) {
// ...
});
Non-chained:
items.find({ type: 'location' }, { sort: { title: 1 }, limit: 42 }).toArray(function(err, data) {
// ...
});
As you can see Non-Chained can accept everything as object, while chained returns cursor after every method and can be reused. So generally you have two options:
For Chained:
var cursor = items.find({ type: 'location' });
if (sort) {
cursor.sort(sort);
}
cursor.toArray(function(err, data) {
// ...
});
For Non-Chained:
var options = { };
if (sort) {
options.sort = sort;
}
items.find({ type: 'location' }, options).toArray(function(err, data) {
// ...
});
It is important to remember that any data from query have to be validated and parsed properly. As well if you are developing API (for example), and will decide to change the way sorting arguments are passed or will want to add new way, then making middleware (in express.js) for parsing this data - is the way to go.
Example for pagination:
function pagination(options) {
return function(req, res, next) {
var limit = options.limit ? options.limit : 0;
var skip = 0;
if (req.query.limit) {
var tmp = parseInt(req.query.limit);
if (tmp != NaN) {
limit = tmp;
}
}
if (req.query.skip) {
var tmp = parseInt(req.query.skip);
if (tmp != NaN && tmp > 0) {
skip = tmp;
}
}
if (options.max) {
limit = Math.min(limit, options.max);
}
if (options.min) {
limit = Math.max(limit, options.min);
}
req.pagination = {
limit: limit,
skip: skip
};
next();
}
}
Usage:
app.get('/items', pagination({
limit: 8, // by default will return up to 8 items
min: 1, // minimum 1
max: 64 // maximum 64
}), function(req, res, next) {
var options = {
limit: req.pagination.limit,
skip: req.pagination.limit
};
items.find({ }, options).toArray(function(err, data) {
if (!err) {
res.json(data);
} else {
next(err);
}
});
});
And url examples:
http://example.com/items
http://example.com/items?skip=64
http://example.com/items?skip=256&limit=32
So it is the way to develop well flexible framework, which does not creates any rules of how things have to be coded as well as solving your challenge.