I want to create new field in my document, lets call it "shelf", it will be an object.
Next I want to make two $set operations - I want to put arrays named "Tom" and "Anna" into my "shelf".
The problem is that I can't match correct query to do that.
I'm using nodejs MongoDB driver.
var myid = 'Tom-Anna'
var TomArray = ["Tom"]
var AnnaArray = ["Anna"]
await db.collection('people').updateOne(
{ pairid: myid },
{ $set: { shelf: TomArray } },
{ upsert: true }
)
await db.collection('people').updateOne(
{ pairid: myid },
{ $set: { shelf: AnnaArray } },
{ upsert: true }
)
Finally, the "shelf" document containing only "AnnaArray", because it's overwriting previously added "TomArray".
I can't add "Tom" and "Anna" array to "shelf" at the same time because content of arrays are generated separately.
I was trying this code:
var name = 'Tom'
var array = ['Tom']
await db.collection('people').updateOne(
{ pairid: myid },
{ $set: { shelf[name]: array } },
{ upsert: true }
)
But it's throwing following error:
{ $set: { shelf[name]: array } },
^
SyntaxError: Unexpected token [
My goal is to set my field like JSON:
"shelf": { "Tom": ["Tom"], "Anna": ["Anna"] }
You can use dot notation to specify nested key name:
var name = 'Tom'
var array = ['Tom']
db.people.update({ pairid: 1 }, { $set: { [`shelf.${name}`]: array } })
Related
I am having an array with following values:
[
{
'Admin1': {
id: 'fa1b2731'
},
'Admin2': {
id: '7b5ab064'
},
'Admin3': {
id: '9f462511'
},
'Admin4': {
id: 'aa82421d'
},
'Admin5': {
id: '34cb2b'
},
'Admin6': {
id: 'ff71ffdd'
},
'Admin7': {
id: 'b57ac9e7'
}
}
]
The code i am trying to retrieve each user id from above array is throwing an error->expected undefined not to be undefined
Following is the code snippet:
if (userArray) {
for (const user of Object.values(userArray)) {
const delUserRes = await userApi.deleteUserById({
token: accessToken,
organizationId: orgid;,
userId: user.id
});
the above method reads the userarray corectly but never assign each id to userId form user.id and throws error
The array in example is having one item, what i mean to get user.id you should call array[0].['Admin1'].id. In your code you doing it like array.['Admin1'].id, so thats why it can't find user.id.
try something like this
if (userArray) {
for (const user of Object.values(userArray[0])) {
const delUserRes = await userApi.deleteUserById({
token: accessToken,
organizationId: orgid;,
userId: user.id
});
Your all the user are in single element of array object at 0 index.
try below code
for (const user of Object.values(userArray[0])) {
console.log(user)
}
Basically you are trying to get values from an object inside an array, so the Object.values doesn't make sense in your code. You can simply use userArray[0] in your for loop or map like:
var data = [ { 'Admin1': { id: 'fa1b2731' }, 'Admin2': { id: '7b5ab064' }, 'Admin3': { id: '9f462511' }, 'Admin4': { id: 'aa82421d' }, 'Admin5': { id: '34cb2b' }, 'Admin6': { id: 'ff71ffdd' }, 'Admin7': { id: 'b57ac9e7' } } ]
Object.values(data[0]).map(user => { //your logic here } );
I want to update an object inside an array of schemas without having to do two requests to the database. I currently am incrementing the field using findOneAndUpdate() if the object already exists and it works fine. but in case the object does not exist then I am having to make another request using update() to push the new object and make it available for later increments.
I want to be able to do only one request (e.g. findOne()) to get the user and then increment the field only if object exists in the array and if not I would like to push the new object instead. then save the document. this way I am only making one read/request from the database instead of two.
this is the function now:
async addItemToCart(body, userId) {
const itemInDb = await Model.findOneAndUpdate(
{
_id: userId,
'cart.productId': body.productId,
},
{ $inc: { 'cart.$.count': 1 } }
);
if (itemInDb) return true;
const updated = await Model.update(
{ _id: userId },
{ $push: { cart: body } }
);
if (updated.ok !== 1)
return createError(500, 'something went wrong in userService');
return true;
}
what I would like to do is:
async addItemToCart(body, userId) {
const itemInDb = await Model.findOne(
{
_id: userId,
'cart.productId': body.productId,
}
);
if (itemInDb) {
/**
*
* increment cart in itemInDb then do itemInDb.save() <<------------
*/
} else {
/**
* push product to itemInDb then save
*/
}
Thank you!
You can try findOneAndUpdate with upsert.
upsert: true then create data if not exists in DB.
Model.findOneAndUpdate(
{
_id: userId,
'cart.productId': body.productId,
},
{ $inc: { 'cart.$.count': 1 } },
{
upsert: true,
}
)
Use $set and $inc in one query.
try {
db.scores.findOneAndUpdate(
{
_id: userId,
'cart.productId': body.productId,
},
{ $set: { "cart.$.productName" : "A.B.C", "cart.$.productPrice" : 5}, $inc : { "cart.$.count" : 1 } },
{ upsert:true, returnNewDocument : true }
);
}
catch (e){
//error
}
reference Link : here
You can use upsert.
upsert is defined as an operation that creates a new document when no document matches the query criteria and if matches then it updates the document. It is an option for the update command. If you execute a command like below it works as an update, if there is a document matching query, or as an insert with a document described by the update as an argument.
Example: I am just giving a simple example. You have to change it according to your requirement.
db.people.update(
{ name: "Andy" },
{
name: "Andy",
rating: 1,
score: 1
},
{ upsert: true }
)
So in the above example, if the people with name Andy is found then the update operation will be performed. If not then it will create a new document.
I try to remove an element from an array attribute of my object.
This is my schema :
const userSchema = new mongoose.Schema({
userID: {
type: Number
},
name: {
type: String
},
names: [
{
text: { type: String, required: true },
order: {
type: Number,
required: true
}
}
]
});
this is my mongoose function :
User.findOne({ userID: Number(req.params.id) })
.then((user) => {
user.names.remove({text: "john", order: 3});
recipe.save(() => {
res.json(recipe);
});
})
I don't understand why it's not good :/
As per documentation of mongoose remove method remove operation is only executed when a callback is passed. To force execution without a callback, you must first call remove() and then execute it by using the exec() method.
Since you are trying to delete from array of objects then better would be to use pull operator. You don't have to do find and remove, you can simply use update method.
As per documentation of $pull operator you can either specify a value or a condition
i.e.
{ $pull: { <field1>: <value|condition>, <field2>: <value|condition>, ... } }
In your scenario you need to either specify complete value of one or more names item object or an condition that matches one or more names item
Add the condition where you match id of names item or if you don't know that then you can use elemMatch to match on few fields i.e.
Use following pull condition to solve the issue:
User.update(
{ _id: Number(req.params.id) },
{ $pull: { 'names': { $elemMatch: { 'text': "john", 'order': 3 }} } },
(error, success) => {
if (error) console.log(error);
console.log(success);
}
);
To Remove Element from array in document please follow as below
User.update(
{
userID: Number(req.params.id),
},
{
$pull: { names: { $elemMatch: { text: "john", order: 3 } } }
},
{
multi: false
}
).lean().then((Status) => {
console.log("Status-->", Status);
res.json('Removed Successfully');
})
Refer $pull operator at link
I have a Javascript Array filled with mean Values and I want to insert them into a collection with a field named "mean". The Field "mean" already exists and has already values in them and now I want to update them with the values of the Array. To be more specific: I want the first Value of the Array to be in the first Document under the field "mean" and so on. I have 98 Documents and the Array has also a length of 98.
The Collection looks like this with the name "cmean":
{
"_id" : "000",
"mean" : 33.825645389680915
}
{
"_id" : "001",
"mean" : 5.046005719077798
}
and the Array:
[
33.89923155012405,
5.063347068609219
]
You can use the forEach method on the array to iterate it and update the collection. Use the index to get the _id to be used in the update query, something like the following:
meansArray.forEach(function(mean, idx) {
var id = db.cmean.find({}).skip(idx).limit(1).toArray()[0]["_id"];
db.cmean.updateOne(
{ "_id": id },
{ "$set": { "mean": mean } },
{ "upsert": true }
);
});
For large collections, you can streamline your db performance using bulkWrite as follows:
var ops = [];
meansArray.forEach(function(mean, idx) {
var id = db.cmean.find({}).skip(idx).limit(1).toArray()[0]["_id"];
ops.push({
"updateOne": {
"filter": { "_id": id },
"update": { "$set": { "mean": mean } },
"upsert": true
}
});
if (ops.length === 1000 ) {
db.cmean.bulkWrite(ops);
ops = [];
}
})
if (ops.length > 0)
db.cmean.bulkWrite(ops);
update({"_id": id}, $set: {"mean": myArray}, function(res, err) { ... });
If you are using mongoose, you also have to change data model from string to array.
I have an object like follows;
var exObj = { 'title' : 'name1'};
some of them have a data property of objects (not an array as I want to reference by name) and look like
exObj = {
title : 'name2',
data : {
prop1 : 'prop1',
prop2 : 'prop2'
}
}
Now I want to add another property to data, sometimes the data property will exist, and sometimes not, but I want to append a property (addedProp) and save it so I will end up with this;
exObj = {
title : 'name2',
data : {
prop1 : 'prop1',
prop2 : 'prop2',
addedProp : 'value'
}
}
When using findOneAndUpdate I can only seem to pass in a whole object which is then appended; something like this is what I currently do.
var data = {};
data.addedProp = value;
Collection.findOneAndUpdate({
title: 'name2'
}, {
data
}, {
upsert: true
})
.exec(function(err) {
if (err) {
console.log(err);
} else {
console.log('Updated');
}
});
But obviously this overides the data object that exists; what is the correct way to do a findOneAndUpdate and make more meaningful changes to the object? I tried casting to toObject() but then I don't have a proper mongoose object to do a .save() on.
To add further clarification; which this worked for simple properties (and worked well) which I know are set; there are some values I wish to add which I need to check if they have a value for the property before adding the property.
So something like this;
Collection.findOneAndUpdate({
field: val
}, {
if (tObj.title) {
title = tObj.title;
}
if (tObj.date) {
release_date = tObj.date;
}
if (tObj.name) {
name = tObj.name;
}
}, { upsert: true
})
.exec(function(err) {
if (err) {
//handler
} else {
//handler
}
});
Your question first seem daunting, but solution is quite simple, you don't need to use $ or upsert, because you are not using any array , so don't need of positional operator or upsert. You can use below code.
Collection.findOneAndUpdate({
title: 'name2'
},{
$set:{"data.prop3":"new prop3"}
})
.exec(function(err) {
if (err) {
console.log(err);
} else {
console.log('Updated');
}
});
It will add prop3 if not exists, or if it exists it will update it. I have checked the code on my local db with update and findOneAndUpdate
You need to use dot notation to target specific fields within an embedded object, building up your update object based on the supplied fields:
var update = {};
if (tObj.title) {
update.title = tObj.title;
}
if (tObj.data) {
if (tObj.data.prop1) {
update['data.prop1'] = tObj.data.prop1;
}
if (tObj.data.prop2) {
update['data.prop2'] = tObj.data.prop2;
}
if (tObj.data.addedProp) {
update['data.addedProp'] = tObj.data.addedProp;
}
}
Collection.findOneAndUpdate({
title: 'name2'
}, {
$set: update
}, {
upsert: true
})
.exec(function(err) {