Node.js Mongodb toggling boolean operator doesnt work - javascript

Hello Im having a weird issue
Ive looked in a few previous questions but ive ran into an issue
Basically I have a document containing a boolean
This boolean is called enabled
Id like to switch it using the findOneAndUpdate function
{ $set: { enabled: { $not: "$enabled" } } }
This is what ive come to according to previous questions
However when I attempt it this is the result
enabled: { '$not': '$enabled' }
Here is my full code
db.findOneAndUpdate({
_id: "Sample"
}, {
$set: {
enabled: {
$not: "$enabled"
}
}
}, {
new: true
}, function(err, result) {})

The problem is that you are trying to use the $not aggregation operator inside of a legacy update.
In order to use aggregation operators you will need to use Updates with Aggregation Pipeline.
For your example, this should be as simple as wrapping the update in an array like:
db.findOneAndUpdate({
_id: "Sample"
},[{
$set: {
enabled: {
$not: "$enabled"
}
}
}], {
new: true
}, function(err, result) {})

You can use the $bit operator to toggle the value of the enabled field.
db.findOneAndUpdate({
_id: "Sample"
}, {
{ $bit: { enabled: { xor: 1 } } }
}, {
new: true
}, function(err, result) {})
On each update, the value enabled will toggle (1 to 0, 0 to 1).
Alternatively, you can use the set method as thus:
db.findOneAndUpdate({
_id: "Sample"
}, [{
$set: {
enabled: {
$not: "$enabled"
}
}
}], {
new: true
}, function(err, result) {})

Related

Is it possible to update multiple documents with different values using mongo? [duplicate]

I have the following documents:
[{
"_id":1,
"name":"john",
"position":1
},
{"_id":2,
"name":"bob",
"position":2
},
{"_id":3,
"name":"tom",
"position":3
}]
In the UI a user can change position of items(eg moving Bob to first position, john gets position 2, tom - position 3).
Is there any way to update all positions in all documents at once?
You can not update two documents at once with a MongoDB query. You will always have to do that in two queries. You can of course set a value of a field to the same value, or increment with the same number, but you can not do two distinct updates in MongoDB with the same query.
You can use db.collection.bulkWrite() to perform multiple operations in bulk. It has been available since 3.2.
It is possible to perform operations out of order to increase performance.
From mongodb 4.2 you can do using pipeline in update using $set operator
there are many ways possible now due to many operators in aggregation pipeline though I am providing one of them
exports.updateDisplayOrder = async keyValPairArr => {
try {
let data = await ContestModel.collection.update(
{ _id: { $in: keyValPairArr.map(o => o.id) } },
[{
$set: {
displayOrder: {
$let: {
vars: { obj: { $arrayElemAt: [{ $filter: { input: keyValPairArr, as: "kvpa", cond: { $eq: ["$$kvpa.id", "$_id"] } } }, 0] } },
in:"$$obj.displayOrder"
}
}
}
}],
{ runValidators: true, multi: true }
)
return data;
} catch (error) {
throw error;
}
}
example key val pair is: [{"id":"5e7643d436963c21f14582ee","displayOrder":9}, {"id":"5e7643e736963c21f14582ef","displayOrder":4}]
Since MongoDB 4.2 update can accept aggregation pipeline as second argument, allowing modification of multiple documents based on their data.
See https://docs.mongodb.com/manual/reference/method/db.collection.update/#modify-a-field-using-the-values-of-the-other-fields-in-the-document
Excerpt from documentation:
Modify a Field Using the Values of the Other Fields in the Document
Create a members collection with the following documents:
db.members.insertMany([
{ "_id" : 1, "member" : "abc123", "status" : "A", "points" : 2, "misc1" : "note to self: confirm status", "misc2" : "Need to activate", "lastUpdate" : ISODate("2019-01-01T00:00:00Z") },
{ "_id" : 2, "member" : "xyz123", "status" : "A", "points" : 60, "misc1" : "reminder: ping me at 100pts", "misc2" : "Some random comment", "lastUpdate" : ISODate("2019-01-01T00:00:00Z") }
])
Assume that instead of separate misc1 and misc2 fields, you want to gather these into a new comments field. The following update operation uses an aggregation pipeline to:
add the new comments field and set the lastUpdate field.
remove the misc1 and misc2 fields for all documents in the collection.
db.members.update(
{ },
[
{ $set: { status: "Modified", comments: [ "$misc1", "$misc2" ], lastUpdate: "$$NOW" } },
{ $unset: [ "misc1", "misc2" ] }
],
{ multi: true }
)
Suppose after updating your position your array will looks like
const objectToUpdate = [{
"_id":1,
"name":"john",
"position":2
},
{
"_id":2,
"name":"bob",
"position":1
},
{
"_id":3,
"name":"tom",
"position":3
}].map( eachObj => {
return {
updateOne: {
filter: { _id: eachObj._id },
update: { name: eachObj.name, position: eachObj.position }
}
}
})
YourModelName.bulkWrite(objectToUpdate,
{ ordered: false }
).then((result) => {
console.log(result);
}).catch(err=>{
console.log(err.result.result.writeErrors[0].err.op.q);
})
It will update all position with different value.
Note : I have used here ordered : false for better performance.

How to conditionally add a field based on match a field with an array Mongo

I'm trying to create a pipeline to add a field based in a condition:
I have a field called helpful which is an array that will contain a list of id's, what I want to do is add a field depending if a given ID is insided that array
an example of the data structure may be this:
{
helpful: [ 5ecd62230a180f0017dc5342 ],
verifiedPurchase: false,
_id: 5f789010e07e4033342c7307,
title: 'text',
body: 'text',
rating: 3,
user: {
_id: 5ecd62230a180f0017dc5342,
name: 'store11',
picture: 'pictureurl'
},
replies: [],
updatedAt: 2020-10-03T18:04:48.026Z,
createdAt: 2020-10-03T14:52:00.410Z,
helpfulCount: 1,
helpfulForMe: false
},
I already tried with this pipeline
{
$addFields:{
helpfulForMe: {
$cond: {
if: {"$in":[user, "$helpful"] } ,
then: true,
else: false,
}
}
}
},
and this one
"$addFields": {
"helpfulForMe" : {
"$in":[
['5ecd62230a180f0017dc5342'], "$helpful"
]
}
}
},
but both returned false even when I set a matching ID
I hope to get a good fix from you guys. Thanks
You can try if your input is array of ids,
$reduce to iterate loop of helpful array and check condition if id in user array then return true otherwise false
let user = ["5ecd62230a180f0017dc5342"];
{
$addFields: {
helpfulForMe: {
$reduce: {
input: "$helpful",
initialValue: false,
in: {
$cond: [{ $in: ["$$this", user] }, true, "$$value"]
}
}
}
}
}
Playground

Changing a array type in mongodb

I am trying to change an array type inside my collection on MongoDB.
title: ['1', '2', '3']
to: [1,2,3]
I already changed at the model to:
title: [{
type: Number,
}],
Already tried:
Users.updateMany({ title: "1" }, { $set: { 'titulos.$': 1} }, { safe: true, upsert: true }, function (err, doc) {
if (err) {
console.log(err);
}
});
Can someone help me ?
Since you're looking for a one-time operation and you're using MongoDB 4.0, the easiest way would be to take advantage of $addFields, $map and $toInt to replace existing title for every user and then run $out to replace exising MongoDB collection (make sure it's named users in your database):
await User.aggregate([
{
$addFields: {
title: {
$map: {
input: "$title",
in: { $toInt: "$$this" }
}
}
}
},
{ $out: "users" }
])

Find and update subdocument, create new one if not exists

I'm pushing an updateOne query to update (or create if not existent) a subdocument. This is my schema
{
accountData: {
userId: Number,
items: [
{
itemId: Number,
purchaseTime: Number
}
]
}
}
and this is an example document
{
accountData: {
userId: 1,
items: [
{
itemId: 2,
purchaseTime: 3
},
{
itemId: 3,
purchaseTime: 5
}
]
}
}
When I run the following bulk query for finding and updating purchaseTime value of itemId's 2 and 4 I get an error. This is the query
let bulkQuery = [];
bulkQuery.push({
updateOne: {
filter: {
'accountData.userId': 1,
'accountData.items.itemId': 2
},
update: {
$inc: {
'accountData.items.$.purchaseTime': 1
}
},
upsert: true,
setDefaultsOnInsert: true
}
});
bulkQuery.push({
updateOne: {
filter: {
'accountData.userId': 1,
'accountData.items.itemId': 4
},
update: {
$inc: {
'accountData.items.$.purchaseTime': 1
}
},
upsert: true,
setDefaultsOnInsert: true
}
});
MyModel.bulkWrite(bulkQuery);
The expected change on the document I provided is increasing purchaseTime of itemId=2 from 3 to 4 and adding a new item object with itemId=4 and purchaseTime=1. However, when I run this, I get the following error
BulkWriteError: The positional operator did not find the match needed
from the query. Unexpanded update: accountData.items.$.purchaseTime

Mongodb $inc embedded value syntax

I'm trying to increment a field in my mongodb document using the $inc operator. The field I am trying to increment is a sub-property of my document's count field, e.g.:
mydoc: {
count: {
schedules: 0
}
}
When I try this:
> db.mydocs.update({ _id: new ObjectId('4db5c2f3dc73c5afdaffd636') }, { $inc: { count.schedules: 1 } }, { upsert: true, safe: true }, null);
from my mongo shell, I get this error message:
Mon Apr 25 11:59:05 SyntaxError: missing : after property id (shell):1
I've tried several syntax variations with similar results. Do I need to take a different approach to this? I've verified my document exists and has a count.schedules field that is set to 0.
I can directly set the value using a command like this:
db.mydocs.update({ _id: new ObjectId('4db5c2f3dc73c5afdaffd636') }, { $set: { count: { schedules:1 } } }, null, null);
But if I try that syntax for the $inc operation, I get this error:
Modifier $inc allowed for numbers only
Thanks
Yes, you can do a $inc only on numbers. Here is how I tried to reproduce your problem, you can notice I've used proper quotes, which is the reason you are seeing the missing : after property id(shell):1 error.
> db.schedules.save({"mydoc": { "count": { "schedules": 0}}});
> db.schedules.find();
{ "_id" : ObjectId("4db5cf199e631c2a52a7c643"), "mydoc" : { "count" : { "schedules" : 0 } } }
> db.schedules.update({ _id: new ObjectId("4db5cf199e631c2a52a7c643") }, { $inc: { "mydoc.count.schedules": 1 } }, { upsert: true, safe: true }, null);
> db.schedules.find();
{ "_id" : ObjectId("4db5cf199e631c2a52a7c643"), "mydoc" : { "count" : { "schedules" : 1 } } }
Hope this helps!
I think this may be a simple fix. Try putting quotes around count.schedules like so:
db.mydocs.update({ _id: new ObjectId('4db5c2f3dc73c5afdaffd636') }, { $inc: { 'count.schedules': 1 } }, { upsert: true, safe: true }, null);

Categories

Resources