Mongoose - replace all array elements - node.js

I want to replace all array's elements in 'prices' filed as below:
{
"name": "My customer name"
"taxCode":123456
"prices":
[
{
"name": "Chocolate",
"unitPrice": 10
},
{
"name": "Cookie",
"unitPrice": 9
}
]
}
The JSON that uses to change 'prices' is:
{
"prices":
[
{
"name": "Chocolate1",
"unitPrice": 10
},
{
"name": "Candy",
"unitPrice": 5
}
]
}
And here is my code to replace the 'prices' array
router.route('/:obj/:id')
.put((req, res) => {
const PObj = require('../models/customer');
PObj.findById(req.params.id, (err, doc) => {
if (err) {
console.log('Lookup error: ' + err);
res.status(500).send('Error');
} else if (doc) {
doc.update({$set: req.body}, (err, task) => {
res.status(200).json(task);
}); } else {
res.status(404).send('Something is wrong');
}
});
});
After code executed is done but without any changes in Mongo DB. Please help me to correct my code. Thank!

If your req.body prints that prices array then it has to be req.body.prices, also rather than fetching the document & updating it - Which is a two- way process, You can try this :
router.route("/:obj/:id").put((req, res) => {
const PObj = require("../models/customer");
PObj.findByIdAndUpdate(
req.params.id, /** this 'req.params.id' has to be `_id` value of doc in string format */
/** internally mongoose will send this as { $set: { prices: req.body.prices }} which will replace `prices` array will new array,
* Just in case if you wanted to push new values, have to manually do { $push: { prices: req.body.prices }} each object */
{ prices: req.body.prices },
{ new: true }, /** returns updated doc, this option is not needed if you don't need doc - by default it returns old doc */
(err, doc) => {
if (err) {
console.log("Lookup error: " + err);
res.status(500).send("Error");
} else if (doc) {
res.status(200).json(task);
} else { /** `doc` value will be null if no doc is not found for given id */
res.status(404).send("Something is wrong");
}
}
);
});
Ref : .findByIdAndUpdate()

Related

deleting an object from array in mongo collection

I have a mongo schema like this.
{
userID:19202,
products:[ { id:020, name:'first' }]
}
I want to pop items from the product array based on id. I used the following command. although it didn't give any error, it also not deleting elements from an array.
userCart.updateOne(
{ userID:userID},
{ $pull: { products: { id:id } } }
)
.then((data) =>
{
if(data)
{
//data is {
"n": 1,
"nModified": 0,
"ok": 1
}
return res.json({
status:true,
message:"cart updated"
})
}
})
Demo - https://mongoplayground.net/p/mh6fXN21vyR
Make sure id and products.id are of the same type as in your document in the database. As your sample, both should be numbers.
if they both are number
db.collection.update({
userID: 19202
},
{
$pull: {
"products": { id: 20 }
}
})
Not Working here - https://mongoplayground.net/p/3zhv8yoH2o9 when "products": { id: "20" }. products.id is a string in the mongo query and in the database in number so mismatched.
Try this one:
db.userCart.update(
{ userID:userID },
{ $pull: { items: { id: 020 } } },
false, // Upsert
true, // Multi
);

how to update an object of an element in array in mongodb?

This is the structure i have, i want to update the nested array element if an object key matches for example - i want to match grnno :"10431000" and update the other keys of that object like vehicle_no,invoice_no etc.
{
"_id" : ObjectId("5f128b8aeb27bb63057e3887"),
"requirements" : [
{
"grns" : [
{
"invoice_no" : "123",
"vehicle_no" : "345",
"req_id" : "5f128c6deb27bb63057e388a",
"grnno" : "10431000"
},
{
"invoice_no" : "abc",
"vehicle_no" : "def",
"req_id" : "5f128c6deb27bb63057e388a",
"grnno" : "10431001"
}
]
}
]
}
I have tried this code
db.po_grn.update({
"requirements.grns.grnno":"10431001"
}, {
$set: {
"requirements.$.grns": {"invoice_no":"test",vehicle_no:"5455"}
}
})
But this is changing the structure i have like this
"requirements" : [
{
"grns" : {
"invoice_no" : "test",
"vehicle_no":"5455"
},
"req_id" : ObjectId("5f128b8aeb27bb63057e3886")
}
],
grns key should be array, and update should be of the particular object which matches the key "grnno". Please help me out. Thanks.
==Edit==
var grnno = req.body.grnno;
db.po_grn.find({
"requirements.grns.grnno":grnno
}).toArray(function(err, po_grn) {
console.log("po_grn",po_grn);
if (po_grn.length > 0) {
console.log("data.grn.grnno ", grnno);
var query = {
requirements: {
$elemMatch: {
"grns.grnno": grnno
}
}
};
var update = {
$set: {
'requirements.$[].grns.$[inner].invoice_no': data.invoice_no,
'requirements.$[].grns.$[inner].vehicle_no': data.vehicle_no,
}
};
var options = {
arrayFilters: [
{ "inner.grnno" : grnno }
]
};
db.po_grn.update(query, update, options
, function(er, grn) {
console.log("grn",grn,"er",er)
res.send({
status: 1,
message: "Grn updated successfully"
});
}
);
} else {
res.send({
status: 0,
message: "Grn not found "
});
}
})
Use a combination of $[] positional-all operator with array filters to update your inner nested document.
var query = {
requirements: {
$elemMatch: {
"grns.grnno": "10431001"
}
}
};
var update = {
$set: {
'requirements.$[].grns.$[inner].invoice_no': "test",
'requirements.$[].grns.$[inner].vehicle_no': "5455",
}
};
var options = {
arrayFilters: [
{ "inner.grnno" : "10431001" }
]
};
db.collection.update(query, update, options);
Update -
NodeJS native MongoDb driver code attached, which is working fine
const { MongoClient } = require('mongodb');
const url = "mongodb://localhost:27017/";
MongoClient.connect(url, function(err, db) {
if (err) {
throw err;
}
const dbo = db.db("test");
(async() => {
const query = {
requirements: {
$elemMatch: {
"grns.grnno": "10431001"
}
}
};
const update = {
$set: {
'requirements.$[].grns.$[inner].invoice_no': "test",
'requirements.$[].grns.$[inner].vehicle_no': "5455",
}
};
const options = {
arrayFilters: [
{ "inner.grnno" : "10431001" }
],
multi: true
};
try {
const updateResult = await dbo.collection("collection").update(query, update, options);
} catch (err) {
console.error(err);
}
db.close();
})();
});

Querying nested object using $find by applying conditions in Mongodb

This is my json object
{
"account_id" : "1",
"sections" : [
"name" : "sec1",
"label" : {
"label1" : "text1",
"label2" : "text2"
}
},
"name" : "sec2",
"label" : {
"label3" : "text3",
"label4" : "text4",
"label5" : "text5"
}
},
]
}
So in this json I wanted to query the label object where sector= sec1. I have used the below code but it didn't work.
var getData = (db, query) => {
return db
.collection(TABLE_NAME)
.find(query, { account_id: { sections: { label: 1 } } })
.toArrayAsync();
};
var dataList = (db, event) => {
let dataQuery = {
account_id: id,
'sections.name': event.params.section
};
return getData(db, dataQuery);
};
module.exports.getData = (event, cb) => {
return using(connectDatabase(), db => {
return dataList (db, event);
}).then(data => cb(null, responseObj(data, 200)), err =>
cb(responseObj(err, 500)));
};
Could someone kindly help me? Thanks inadvance.
Try something like this. use $project, we can selectively remove or retain field and we can reassign existing field values and derive entirely new values. after projecting the labels and name do a $match to extract the document by name. One thing to notice is that by using $project,it will automatically assign the document's _id.
var dataList = (db, event) => {
return db
.collection(TABLE_NAME)
.aggregate([
{
$match: { account_id: your_id }
},
{
$unwind: '$sections'
},
{
$project:{labels:'$sections.label',name:'$sections.name'}
},
{
$match:{name:section_name}
}]).toArray();
};
You have to use aggregate method with $unwind syntax to find item in array of object.
var dataList = (db, event) => {
return db
.collection(TABLE_NAME)
.aggregate([
{
$match: {
account_id: id,
}
},
{ $unwind: "$comments" },
{
$match: {
'name': event.params.section
}
}
])
.toArrayAsync();
};
Result:
[{
"account_id": "1",
"sections": {
"name": "sec2",
"label": {
"label3": "text3",
"label4": "text4",
"label5": "text5"
}
}
}]

mongoDB and sails aggregate dont work with nodejs

I'm using mongodb and sails framework, Production.find({}) is working normally
but Production.aggregate([]) is returning an error
Production.aggregate() is not a function
module.exports = {
list : function(req,res) {
Production.aggregate([{
$project: {
data: { $substr: ["$pt",0,10] },
prodTempo: { $substr: ["$sis",0,10]}
}
}])
.exec(function(err,collection ){
if(err){
res.send(500,{error:"DataBase Error"});
}
res.view('list',{producao:collection});
});
}
};
As of Sails v1.0 the .native() method is deprecated in favor of getDatastore().manager.
https://sailsjs.com/documentation/reference/waterline-orm/models/native
Due to a bug with the current version of sails-mongo (v1.0.1) which doesn't support the new required cursor method I've actually switched to using Mongo View's to manage aggregate queries.
The pattern below is "supposed" to work but currently returns no results because toArray() of an aggregate() function is currently not properly supported. It returns an AggregateCursor which does not support the toArray() method.
WHAT I ENDED UP DOING
const myView = sails.getDatastore().manager.collection("view_name");
myView.find({...match/filter criteria...}).toArray((err, results) => {
if (err) {
// handle error 2
}
// Do something with your results
});
The entire Aggregate query I put into the Mongo DB View and added additional columns to support filter/match capabilities as needed. The only portion of "match" I did not place into Mongo are the dynamic fields which I use above in the find() method. That's why you need the additional fields since find() will only query the columns available in the query and not the underlying model
WHAT SHOULD HAVE WORKED
So the pattern for aggregate would now be as follows:
const aggregateArray = [
{
$project: {
data: { $substr: ['$pt', 0, 10] },
prodTempo: { $substr: ['$sis', 0, 10] }
}
}
];
sails.getDatastore('name of datastore').manager.collection('collection name')
.aggregate(aggregateArray)
.toArray((err, results) => {
if (err) {
// handle error 2
}
// Do something with your results
});
For aggregations you need to call the native function first. Then it looks like this:
const aggregateArray = [
{
$project: {
data: { $substr: ['$pt', 0, 10] },
prodTempo: { $substr: ['$sis', 0, 10] }
}
}
];
Production.native(function(err, prodCollection) {
if (err) {
// handle error 1
} else {
prodCollection
.aggregate(aggregateArray)
.toArray((err, results) => {
if (err) {
// handle error 2
}
// Do something with your results
});
}
});
const regexForFileName = '.*' + fileName + '.*';
var db = model.getDatastore().manager;
var rawMongoCollection = db.collection(model.tableName);
rawMongoCollection.aggregate(
[
{
$project : {
"_id" : 0,
"fileId" : 1,
"fileName" : 1,
"fileSize" : 1,
"createdTime" : 1
}
},
{
$match : {
"fileName" : {
$regex: regexForFileName,
$options: 'i'
}
}
},
{
$sort: {
"createdTime" : -1
}
},
{
$skip: pageNumber * numberOfResultsPerPage
},
{
$limit: numberOfResultsPerPage
}
]
).toArray((err, results) => {
if (err) {
console.log(err);
}
console.log("results: " + JSON.stringify(results));
});

Elastic search delete operation

Am new to elastic search and struggling to delete an entry from my collection.
I need a query similar to this one
DELETE FROM message WHERE id='1323'" and created_user = "user#gmail.com".
Following are my elastic search query, when i execute this, its only deleting the particular id field, its not taking the second argument created_user. Please help me to solve this issue. Thanks
var created = "9ed8afe738aa63c28b66994cef1f83c6"
db.delete({
index: 'outboxpro',
type: 'message',
id: req.body.post_id,
created_user: created
}, function (error, resp) {
if (error) {
return next(error);
}
var data = {};
console.log('delete response',resp);
if (resp.hits.successful < 1) {
data = {status: false, message: 'NO POST FOUND TO DELETE', code: 400};
res.send(data);
} else {
return next({status: true, message: 'POST DELETED', data: error, code: 500});
}
});
//// EDIT
I have tried deleteByQuery, following are my code
db.deleteByQuery({
index: 'outboxpro',
type: 'message',
body:{
"query": {
"filtered": {
"query": {
"match": {
"_id": {
"query": "Kal4AXi5R9G-IMx4GIKYMw"
}
}
},
"filter": {
"and": [
{
"term": {
"created_user": created
}
}
]
}
}
}
}
}, function (error, resp) {
if (error) {
return next(error);
}
console.log('post deleted');
});
You can delete documents matching your query, using delete by query in elasticsearch.. Refer
http://www.elasticsearch.org/guide/en/elasticsearch/client/javascript-api/current/api-reference-1-0.html#api-deletebyquery-1-0
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-delete-by-query.html
db.deleteByQuery({
index: 'outboxpro',
type: 'message',
body: {
"query": {
"filtered": {
"query": {
"match": {
"_id": "Kal4AXi5R9G-IMx4GIKYMw"
}
},
"filter": {
"term": {
"created_user": "created"
}
}
}
}
},
function (error, resp) {
if (error) {
return next(error);
}
console.log('post deleted');
});
The delete API will do exactly what you want, just in a slightly round-about way.
What you'll have to do first is search for the documents you want to delete, so construct a search query that find all documents with the id of '1323' and a created_user of 'user#gmail.com'. From the returned documents you'll be able to retreive the document ID which you then need to pass through to the delete API.
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-delete.html

Resources