Product
.findAll()
.then((products) => {
/* Perform operations */
}
The above query returns an array of products. For eg,
[
{
name: Mobile,
price: 10000
},
{
name: Laptop,
price: 20000
},
]
I need to make some changes to the products array (add new fields based on the values of existing fields, and delete those existing fields). I tried few methods, but none are working:
products.forEach((product) => {
product.[updatedPrice] = updatedPrice;
delete product[price];
}
Array.map() is also not working.
The following works, but I don't know the working behind, and why it is happening. Also, how to delete a field using the same.
products.forEach((product) => {
product.set('updatedPrice', updatedPrice, {strict: false})
}
The thing here to note is that in .then((products) products object here is not a JSON object but a Mongoose Document object and the set method you are using is defined by the mongoose. You can refer it from here https://mongoosejs.com/docs/guide.html#strict
We can do 2 things:
use lean() (returns a plain js object)
Product.findAll().lean().then((products) => {
/* Perform operations*/
});
use toJSON() method on products object to convert mongoose object to js object
Product.findAll().then((products) => {
products = products.toJSON();
/* Perform operations*/
});
Thanks
Related
I just can't figure out the query and even if it's allowed to write a single query to push 4 different objects into 4 different arrays deeply nested inside the user Object.
I receive PATCH request from front-end which's body looks like this:
{
bodyweight: 80,
waist: 60,
biceps: 20,
benchpress: 50,
timestamp: 1645996168125
}
I want to create 4 Objects and push them into user's data in Mongo Atlas
{date:1645996168125, value:80} into user.stats.bodyweight <-array
{date:1645996168125, value:60} into user.stats.waist <-array
...etc
I am trying to figure out second argument for:
let user = await User.findOneAndUpdate({id:req.params.id}, ???)
But i am happy to update it with any other mongoose method if possible.
PS: I am not using _id given by mongoDB on purpose
You'll want to use the $push operator. It accepts paths as the field names, so you can specify a path to each of the arrays.
I assume the fields included in your request are fixed (the same four property names / arrays for every request)
let user = await User.findOneAndUpdate(
{ id: req.params.id },
{
$push: {
"stats.bodyweight": {
date: 1645996168125,
value: 80,
},
"stats.waist": {
date: 1645996168125,
value: 60,
},
// ...
},
}
);
If the fields are dynamic, use an object and if conditions, like this:
const update = {};
if ("bodyweight" in req.body) {
update["stats.bodyweight"] = {
date: 1645996168125,
value: 80,
};
}
// ...
let user = await User.findOneAndUpdate(
{ id: req.params.id },
{
$push: update,
}
);
The if condition is just to demonstrate the principle, you'll probably want to use stricter type checking / validation.
try this:
await User.findOneAndUpdate(
{id:req.params.id},
{$addToSet:
{"stats.bodyweight":{date:1645996168125, value:80} }
}
)
I want to be able to update an array of objects where each object has a new unique value assigned to it.
Here is a simplified example of what I'm doing. items is an array of my collection items.
let items = [{_id: '903040349304', number: 55}, {_id: '12341244', number: 1166}, {_id: '667554', number: 51115}]
I want to assign a new number to each item, and then update it in collection:
items = items.map(item => {
item.number = randomInt(0, 1000000);
return item;
})
What would be the best way to update the collection at once? I know that I could do it in forEach instead of map, how ever this seems as a dirty way of doing it, as it won't do the bulk update.
items.forEach(async (item) => {
await this.itemModel.update({_id: item._id}, {number: randomInt(0, 1000000)})
});
I've checked the updateMany as well but my understanding of it is that it's only used to update the documents with a same new value - not like in my case, that every document has a new unique value assigned to it.
After a bit of thinking, I came up with this solution using bulkWrite.
const updateQueries = [];
items.forEach(async (item) => {
updateQueries.push({
updateOne: {
filter: { _id: item._id },
update: { number: item.number },
},
});
});
await this.itemModel.bulkWrite(updateQueries);
About bulkWrite
Sends multiple insertOne, updateOne, updateMany, replaceOne,
deleteOne, and/or deleteMany operations to the MongoDB server in one
command. This is faster than sending multiple independent operations
(like) if you use create()) because with bulkWrite() there is only one
round trip to MongoDB.
You can call an aggregate() to instantly update them without needing to pull them first:
Step1: get a random number with mongoDb build in $rand option which returns a number between 0 and 1
Step2: $multiply this number by 1000000 since that is what you defined ;)
Step3: use another $set with $floor to remove the decimal portion
YourModel.aggregate([
{
'$set': {
'value': {
'$multiply': [
{
'$rand': {}
}, 1000000
]
}
}
}, {
'$set': {
'value': {
'$floor': '$value'
}
}
}
])
Here a picture of how that looks in mongo Compass as a proof of it working:
I am trying to write a transaction that first query documents by documentId from a list of ids, then makes some updates.
I am getting the error:
The corresponding value for FieldPath.documentId() must be a string or a DocumentReference.
For example:
const indexArray = [..list of doc ids...]
const personQueryRef = db.collection("person").where(admin.firestore.FieldPath.documentId(), "in", indexArray)
return db.runTransaction(transaction => {
return transaction.get(personQueryRef).then(personQuery => {
return personQuery.forEach(personRef => {
transaction.update(personRef, { ...update values here })
//more updates etc
})
})
})
I am wanting to do this in an onCreate and onUpdate trigger. Is there another approach I should be taking?
Update
The error still persists when not using a transaction, so this is unrelated to the problem.
The problem does not occur when the query is .where(admin.firestore.FieldPath.documentId(), "==", "just_one_doc_id"). So, the problem is with using FieldPath.documentId() and in.
It sounds like the type of query you're trying to do just isn't supported by the SDK. Whether or not that's intentional, I don't know. But if you want to transact with multiple documents, and you already know all of their IDs, you can use getAll(...) instead:
// build an array of DocumentReference objects
cost refs = indexArray.map(id => db.collection("person").doc(id))
return db.runTransaction(transaction => {
// pass the array to getAll()
return transaction.getAll(refs).then(docs => {
docs.forEach(doc => {
transaction.update(doc.ref, { ...update values here })
})
})
})
I am executing a mongoose Model.findById() function in order to return a single instance by utilizing an express route.
Model.findById(modelid)
.then(instance => {
if(instance.isOwnedBy(user)) {
return instance.update({$push: {days: req.params.dayid}}, {new: true})
.then(foo => res.send(foo))
} else {
res.status(401).send("Unauthorized")
}
})
the above code returns an object containing the opTime, electionId...etc instead of returning the newly updated document instance. How am I able return the newly updated document after the instance.update() method?
If instance.isOwnedBy(user) and _id: modelid can be merged into one mongo query, it's better to use findOneAndUpdate() but in that way, if it doesn't find any document match, you can not know which part of the query causes the not found.
And because I don't know much about your models, conditions, I can not answer how to do it with findOneAndUpdate() but there is another way that modify the document and call save() method.
Example base on your code:
Model.findById(modelid)
.then(instance => {
if(instance && instance.isOwnedBy(user)) {
if(instance.days) instance.days.push(req.params.dayid);
else instance.days = [req.params.dayid];
instance.save().then(function(instance){
res.send(instance);
})
} else {
res.status(401).send("Unauthorized")
}
})
Note: You should check if the instance exist or not before modify it.
I am using mongodb to store the data.
I have a field "campus" to hold the ObjectIds of Campus data.
Intially the user had a single campus, but later on the type of campus had to be modified to hold an array of campus. But the initial records remained to be the same.
Now while I'm trying to push a new campusId, some records are not updating because of type change.
I have some 500 records in which some records have single objectId and in some records the campus is an array of ObjectIds.
Like this,
"campusIds" : ObjectId("5c8f304a4350a990f7c40")
And,
"campusIds" : [
ObjectId("5d136de2a02b2c14947652"),
ObjectId("5d136f0da02b2c14947656"),
ObjectId("5d137082a02b2c14947658"),
ObjectId("5d14520da02b2c1494765c"),
ObjectId("5d1459dd81801aef0865a8") ]
I cannot manaully change the records in mongodb as the records in large number.
Is there a way I can change the field to an array in my db?
Create a query which only filters documents where the field exists and it's of ObjectId type ($type 7). The results from this query can then be used to do a bulk update on the collection.
The following async operation does the above:
(async () => {
try {
const docs = await db.collection('collectionName').find({
'campus': {
'$exists': true,
'$type': 7
}
}).toArray()
const ops = docs.map(({ _id, campus }) => ({
'updateOne': {
'filter': { _id } ,
'update': { '$set': { 'campusIds': [campus] } }
}
}))
db.collection('collectionName').bulkWrite(ops)
} catch(err) {
// handle error
}
})()