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" }
])
Related
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) {})
So I tried several ways, but I can't, I can modify several objects with the same key but I can't modify any with different keys, if anyone can help me is quite a complex problem
{
id: 123,
"infos": [
{ name: 'Joe', value: 'Disabled', id: 0 },
{ name: 'Adam', value: 'Enabled', id: 0 }
]
};
In my database I have a collection with an array and several objects inside which gives this.
I want to modify these objects, filter by their name and modify the value.
To give you a better example, my site returns me an object with the new data, and I want to modify the database object with the new object, without clearing the array, the name key never changes.
const object = [
{ name: 'Joe', value: 'Hey', id: 1 },
{ name: 'Adam', value: 'None', id: 1 }
];
for(const obj in object) {
Schema.findOneAndUpdate({ id: 123 }, {
$set: {
[`infos.${obj}.value`]: "Test"
}
})
}
This code works but it is not optimized, it makes several requests, I would like to do everything in one request, and also it doesn't update the id, only the value.
If anyone can help me that would be great, I've looked everywhere and can't find anything
My schema structure
new Schema({
id: { "type": String, "required": true, "unique": true },
infos: []
})
I use the $addToSet method to insert objects into the infos array
Try This :
db.collection.update({
id: 123,
},
{
$set: {
"infos.$[x].value": "Value",
"infos.$[x].name": "User"
}
},
{
arrayFilters: [
{
"x.id": {
$in: [
1
]
}
},
],
multi: true
})
The all positional $[] operator acts as a placeholder for all elements in the array field.
In $in you can use dynamic array of id.
Ex :
const ids = [1,2,..n]
db.collection.update(
//Same code as it is...
{
arrayFilters: [
{
"x.id": {
$in: ids
}
},
],
multi: true
})
MongoPlayGround Link : https://mongoplayground.net/p/Tuz831lkPqk
Maybe you look for something like this:
db.collection.update({},
{
$set: {
"infos.$[x].value": "test1",
"infos.$[x].id": 10,
"infos.$[y].value": "test2",
"infos.$[y].id": 20
}
},
{
arrayFilters: [
{
"x.name": "Adam"
},
{
"y.name": "Joe"
}
],
multi: true
})
Explained:
You define arrayFilters for all names in objects you have and update the values & id in all documents ...
playground
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.
I have an object and the server will receive a user_id and a part_id. I need to get the certain user, then filter the parts by the provided part ID and get the price.
{
_id: 6086b8eec1f5325278846983,
user_id: '13',
car_name: 'Car name 1',
created_at: 2008-11-25T00:46:52.000Z,
parts: [
{
_id: 6086ee212681320190c3c8e0,
part_id: 'P456',
part_name: 'Part name 1',
image: 'image url',
stats: {
price: 10,
}
},
{
_id: 6087e7795e2ca925fc6ead27,
part_id: 'P905',
part_name: 'Part name 2',
image: 'image url',
stats: {
price: 15,
}
}
]
}
I tried to run the following, but ignores the part_id filter and returns every parts in the array.
Custumers.findOne({'user_id': '13', 'parts.part_id': 'P456'})
Also tried with aggregate but still no luck.
Customers.aggregate([
{ $match: { 'user_id': '13'}}
]).unwind('parts')
I checked the mongoose documentation but cannot wrap my head around it. Please let me know what I am missing.
Mongoose version: 5.12.4
Option - 1
This will work if you've only 1 matching parts
$ (projection)
The $ operator projects the first matching array element from each document in a collection based on some condition from the query statement.
Demo - https://mongoplayground.net/p/tgFL01fK3Te
db.collection.find(
{ "user_id": "13", "parts.part_id": "P456" },
{ "parts.$": 1, car_name: 1 } // add fields you need to projection
)
Option -2
$unwind
Demo - https://mongoplayground.net/p/_PeP0WHVpJH
db.collection.aggregate([
{
$match: {
"user_id": "13",
"parts.part_id": "P456"
}
},
{
$unwind: "$parts" // break into individual documents
},
{
$match: {
"parts.part_id": "P456"
}
}
])
I'm trying to update a value inside my array of objects.
Looking at the above mongoDB schema what I want is:
Find an expense with the ID match with the _id and need to update the fields with new ones from the req.body.
Just need to update the: expensesType, description, price and status.
The following code is what I tried to do.
First I need to match the right expense and it works fine but when I try to house.save() show me a message 'house.save is not a function'. So I think maybe I need to use a mongoDB function to get the result.
router.put("/editExpense/:id", ensureAuthenticated, (req, res) => {
var id = mongoose.Types.ObjectId(req.params.id);
House.find(
{ "expensesHouse._id": id },
{
members: 1,
name: 1,
description: 1,
address: 1,
type: 1,
user: 1,
userID: 1,
userType: 1,
expensesHouse: { $elemMatch: { _id: id } },
date: 1
}
).then(house => {
console.log(house);
expenseType = req.body.expenseType;
description = req.body.description;
price = req.body.price;
status = req.body.status;
house.save().then(() => {
req.flash("success_msg", "Expenses Updated");
res.redirect("/houses/dashboard");
});
});
});
****** UPDATED ******
After a search I found this updateOne and after adjusts, this is my final result but this way I delete every record..
router.put("/editExpense/:id", ensureAuthenticated, (req, res) => {
var id = mongoose.Types.ObjectId(req.params.id);
House.updateOne(
{ "expensesHouse._id": id },
{
members: 1,
name: 1,
description: 1,
address: 1,
type: 1,
user: 1,
userID: 1,
userType: 1,
expensesHouse: { $elemMatch: { _id: id } },
date: 1
},
{ $set: { "expensesHouse.expenseType": req.body.expenseType } }
).then(house => {
req.flash("success_msg", "Expenses Updated");
res.redirect("/houses/dashboard");
});
});
*********** RESOLUTION ***********
I just fixed the problem the way I show below.
House.updateOne(
{ "expensesHouse._id": id },
{
$set: {
expensesHouse: {
expenseType: req.body.expenseType,
description: req.body.description,
price: req.body.price,
status: req.body.status
}
}
}
You are really close to the answer the problem right now that you are having is syntax difference between find and UpdateOne
This is what Find expects, Check MongoDB docs
db.collection.find(query, projection)
This is what updateOne expects, Check Mongo docs
db.collection.updateOne(
<filter>,
<update>,
{
upsert: <boolean>,
writeConcern: <document>,
collation: <document>,
arrayFilters: [ <filterdocument1>, ... ],
hint: <document|string> // Available starting in MongoDB 4.2.1
}
)
See the Difference? Second parameter should be update not projection because Update one
returns
matchedCount containing the number of matched documents
modifiedCount containing the number of modified documents
upsertedId containing the _id for the upserted document.
A boolean acknowledged as true if the operation ran with write concern or false if write concern was disabled.
So Your code should be
House.updateOne(
{ "expensesHouse._id": id },
{ $set: { "expensesHouse.expenseType": req.body.expenseType } }
).then(house => {
req.flash("success_msg", "Expenses Updated");
res.redirect("/houses/dashboard");
});
});
House.findOneAndUpdate({userId : req.params.userId},
{ $set: { "expensesHouse.$[element].status": req.body.status } },
{ multi:true, arrayFilters: [{ "element.userID" : req.params.subUserId }], new:true })
Your Api reuquest consist of both the IDs (outer as well as inner) like /api/update/:userId/:subUserId