Conflict when updating a document with both $set and $currentDate - node.js

I’m using Mongo 3.6.3 and I have a database with a collection and an item with _id equal to 1.
I want to update the item by adding an object and a timestamp inside of that object. However, I get an error. Here’s what I do:
function MyObject() {
this.bar = {
apples: 4,
bananas: 5
};
}
collection.update({
_id: 1
}, {
$set: {
"foo": new MyObject()
},
$currentDate: {
"foo.time": {
$type: 'timestamp'
}
}
}, function (err) {
console.log(err.name, err.message);
});
and I get:
MongoError Updating the path 'foo.time' would create a conflict at 'foo'
Why does that happen?
If I run the $set operation first and then the $currentDate one in another update(), I get the desired result:
{
"_id" : 1,
"foo" : {
"bar" : {
"apples" : 4,
"bananas" : 5
},
"time" : Timestamp(1523459420, 1)
}
}
However, if I try to do them simultaneously like I’ve shown in the code above, I get the error. Why?

You can't have multiple operators ($set and $currentDate) that modify the same path (foo in this case). In your case you could use dot notation though:
collection.update({
_id: 1
}, {
$set: {
"foo.bar.apples": 4,
"foo.bar.bananas": 5
},
$currentDate: {
"foo.time": {
$type: 'timestamp'
}
}
}, function (err) {
console.log(err.name, err.message);
});
or just change MyObject to set this.time = new Date() instead of using $currentDate.

Related

MongoDB updating array of objects does not work as expected

Got multiple documents in a db one of which looks like this:
{
"searchWord":[
"pizz",
"pizza"
],
"result":[
{
"idMeal":1,
"strMeal":"test1",
"strInstructions":"test1"
},
{
"idMeal":2,
"strMeal":"test2",
"strInstructions":"test2"
}
]
}
Tried to solve it like this:
eg:
db.meals.updateOne(
{
"searchWord": "pizz",
"result": { $elemMatch: { idMeal: "1" } }
},
{ $set: { 'result.$.strMeal' : "UPDATED" } }
)
This doesnt update the respective subdocument only the 2nd as if I wrote
{ $set: { 'result.1.strMeal' : "UPDATED" } }
(Which will result in the 2nd subdocument being updated)
This is the other idea (Same result)
db.meals.updateOne(
{ searchWord: "pizz", 'result.idMeal': 319012 },
{ $set: { "result.$.strMeal" : "fsdf" } }
)
What I dont seem to understand is its exactly the syntax that is provided by mongo yet it doesnt work
The "$" operator doesnt pick up which array of objects I wanna update
Try to use $[] in your $set for multiple positional element
db.collection.update({
"searchWord": "pizz"
},
{
$set: {
"result.$[r].strMeal": "UPDATED"
}
},
{
arrayFilters: [
{
"r.idMeal": 1
}
]
})
Here is the Mongo playground for your reference.

MongoDB return nested array of objects minus a property within the object (also .then() doesn't work with aggregation)

I'm very new to mongodb and am having difficulty getting to a solution for my use case. For example I have the following document:
{
_id : ObjectId('5rtgwr6gsrtbsr6hsfbsr6bdrfyb'),
uuid : 'something',
mainArray : [
{
id : 1,
title: 'A',
array: ['lots','off','stuff']
},
{
id : 2,
title: 'B',
array: ['even','more','stuff']
}
]
}
I'd like to have the following returned:
{
uuid : 'something',
mainArray : [
{
id : 1,
title: 'A'
},
{
id : 2,
title: 'B'
}
]
}
I've tried various combinations of using findOne() and aggregate() with $slice and $project. With findOne(), if it worked at all, the who document would be returned. I am unable to test whether attempts at aggregating work because .then((ret)=>{}) promises don't seem to work in node.js for me with it (no issues with findOne). Calling a function like so
return db.myCollection.aggregate([
{
$match: {
_id:ObjectId(mongo_id)
}
},
{
$project : {
mainArray: {
id:1,
title:1
}
}
}
],function(err,res){
console.log(res)
return res
})
logs the entire function and not the droids I'm looking for.
You're missing toArray() method to obtain the actual result set. Instead you're returning the aggregation cursor object. Try this.
return db.myCollection.aggregate([matchCode,projectCode]).toArray().then(
data => {
console.log(data);
return data;
},
error => { console.log(error)});
The documnetation on aggregation cursor for MongoDB NodeJS driver can
be found here
http://mongodb.github.io/node-mongodb-native/3.5/api/AggregationCursor.html#toArray
This is an alternative solution (to the solution mentioned in the comment by #v1shva)
Instead of using aggregation you can use projection option of .findOne() operation.
db.myCollection.findOne(matchCode, {
projection: { _id: false, 'mainArray.array': false } // or { _id: -1, 'mainArray.array': -1 }
})

Mongoose: update an element of an array of a specific document

I am having a collection of documents called 'company'.
company 1 -
{
_id: '1',
data:[
{_id:'11', value: 'emp11'},
{_id:'12', value: 'emp12'}
]
}
company 2-
{
_id: '2',
data:[
{_id:'21', value: 'emp21'},
{_id:'22', value: 'emp22'}
]
}
Now I want to update value 'emp11' to 'emp99'.
I'm following this approach-
companyModel.findById('1', function(err, company) {
return company.data.update(
{_id: '11'},
{$set: {value: 'emp99'}}
);
});
I'm able to get the company but after that it's showing an error-
company.data.update is not a function
Please suggest a possible solution.
companyModel.update(
{ "_id" : :"1", "data._id": "11" },
{ "$set": { "data.$.value": "emp99" }},
function(err, company) {
console.log(company)
})
There is no need to use findById, you can use this directly.
In mongo update you need to search for both the document and the field you want to update.
The field you want to update is essential as it is used to locate the position of the array when you use $.
However you can do it as following also :
companyModel.findById('1', function(err, company) {
for(var i =0; i< company.data.length; i++)
if(company.data._id === "11")
break;
if(i<company.data.length)
company.data[i].value = 'emp99'
company.save()
});
db.company.update({
_id: "1",
data: {
$elemMatch: {
value: 'emp11'
}
}
}, {
$set: {
'data.$.value': 'emp99'
}
})

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

$pulling an object from an array based on _id in Mongoose [duplicate]

Doc:
{
_id: 5150a1199fac0e6910000002,
name: 'some name',
items: [{
id: 23,
name: 'item name 23'
},{
id: 24,
name: 'item name 24'
}]
}
Is there a way to pull a specific object from an array? I.E. how do I pull the entire item object with id 23 from the items array.
I have tried:
db.mycollection.update({'_id': ObjectId("5150a1199fac0e6910000002")}, {$pull: {id: 23}});
However I am pretty sure that I am not using 'pull' correctly. From what I understand pull will pull a field from an array but not an object.
Any ideas how to pull the entire object out of the array.
As a bonus I am trying to do this in mongoose/nodejs, as well not sure if this type of thing is in the mongoose API but I could not find it.
try..
db.mycollection.update(
{ '_id': ObjectId("5150a1199fac0e6910000002") },
{ $pull: { items: { id: 23 } } },
false, // Upsert
true, // Multi
);
I have a document like
I have to delete address from address array
After searching lots on internet I found the solution
Customer.findOneAndUpdate(query, { $pull: {address: addressId} }, (err, data) => {
if (err) {
return res.status(500).json({ error: 'error in deleting address' });
}
res.json(data);
});
my database:
{
"_id" : ObjectId("5806056dce046557874d3ab18"),
"data" : [
{ "id" : 1 },
{ "id" : 2 },
{ "id" : 3 }
]
}
my query:
db.getCollection('play_table').update({},{$pull:{"data":{"id":3}}},{multi:true}
output:
{
"_id" : ObjectId("5806056dce046557874d3ab18"),
"data" : [
{ "id" : 1 },
{ "id" : 2 }
]
}
You can try it also:
db.getCollection('docs').update({ },{'$pull':{ 'items':{'id': 3 }}},{multi:true})
For a single record in array:
db.getCollection('documents').update(
{ },
{'$pull':{ 'items':{'mobile': 1234567890 }}},
{new:true}
);
For a multiple records with same mobile number in array:
db.getCollection('documents').update(
{ },
{
$pull: {
items: { mobile: 1234567890 }
}
},
{ new:true, multi:true }
)
Use $pull to remove the data
return this.mobiledashboardModel
.update({"_id": args.dashboardId}, { $pull: {"viewData": { "_id": widgetId}}})
.exec()
.then(dashboardDoc => {
return {
result: dashboardDoc
}
});
Kishore Diyyana:
If you want to remove all elements including the key of the element attributes list.
Here is the example of mongoDB unset operator:
db.UM_PREAUTH_CASE.update(
{ 'Id' : 123}, { $unset: { dataElements: ""} } )
JSON Look like this:
{ "Id":123,"dataElements" : [ { "createdBy" : "Kishore Babu Diyyana", "createdByUserId" : 2020 }, { "createdBy" : "Diyyana Kishore", "createdByUserId" : 2021 } ] }

Resources