Update child element on mongodb - mongodb

I've got a little problem with mongodb update method. This is my (simplified) schemas:
{
profile: {
birthdate: "XXX",
city: "xxx"
},
account: {
username: "...",
password: "....",
visits: 0
}
}
I've got 2000 objects in DB. I want to anonymize datas by removing username values.
I tried this:
db.users.update({}, {$set: account: {username: ""}}, false, true);
That doesn't works, this query remove password field and visits. I understand why, but how to do ?
db.users.update({}, {account: { $set: {username: ""}}}, false, true);
mongo want to assign "$set" field, so that dosen't work.
My question is: how to update descendant fields without removing the entire "account" subdocument ?
(Setting "upsert" to true does the same.)

You should use:
$set:{"account.username":""}
Just wondering why you don't use $unset?

Related

Unique and id is getting null in Moongose update/upsert

I have one schema like this:
export const HotelSchema = new mongoose.Schema({
name: String,
firstName: String,
email: { type: String, unique: true },
canLogin: Boolean
},
{
collection: "hotels"
}
);
and to add/update I am using this query:
this.hotelModel.updateOne({ _id: hotel._id }, hotel, { upsert: true });
Where hotel object I am passing:
{
"email" : "er.markar#gmail.com",
"name" : "sunny123"
}
But it is inserting duplicate emails with _id as null:
Even I tried findOneAndUpdate. tried autoIndex in the email schema. Still not working.
Am I missing something?
See https://mongoosejs.com/docs/validation.html#the-unique-option-is-not-a-validator
Infact, you should use unique index on a field. That works!
You are passing email and name, but you are not passing "_id", so "hotel._id" will not be found. Instead you should do as follows:
this.hotelModel.updateOne({ email:hotel.email}, hotel, { upsert:true});

MongoDB - how I add a UUID column to existing collection based on values from current entries?

I have 'Users' collection which has two columns, '_id' and 'userName', both of type string.
I want to add third column 'UserId' which will be UUID wrapping the id from _id column.
Tried few ways but without any success.
For example:
{
_id: "fe83f869-154e-4c26-a5db-fb147728820f",
userName: "alex"
}
I want it to be:
{
_id: "fe83f869-154e-4c26-a5db-fb147728820f",
userName: "alex",
UserId: UUID("fe83f869-154e-4c26-a5db-fb147728820f")
}
I tried something like:
db.Users_temp.update(
{},
{ $set: {"UserId": UUID("$_id") } },
false,
true
)
But it results in columns with value UUID("----")
Will appreciate any help.
Ok,
Found a solution to my problem.
db.Users_temp.find().forEach(function(user) {
db.Users_temp.update(
{"_id" : user._id},
{ "$set": {"UserId": UUID(user._id)} }
)
})
this will work
i am not sure why but this works only with set operation as an array rather than as a object
db.Users_temp.update({},[{$set: {'UserId': '$_id'}}])

update Object inside array of Object with mongoose

I'm trying to update and object inside array in MongoDB.
my model is:
let userSchema = new mongoose.Schema({
userName: {
type: String
},
password: {
type: String
},
history: []
});
And inside history each element is from the next type:
id, array(named ing_array) and boolean field called favorite.
I'm trying to update the favorite field with mongoose with the userName and the id.
I tried to do this query and I didn't succed.
Could some one tell me whats worng?
[object photo]: https://i.stack.imgur.com/2mYpP.png
User.findOneAndUpdate(
{ "userName": user_name, "history.id": id },
{ "$set": { "history.$.favorite": true }}
);
You have to use arrayFilters in this way:
db.collection.update({
"userName": "uname",
"history.id": 1
},
{
"$set": {
"history.$[element].favorite": false
}
},
{
"arrayFilters": [
{
"element.id": 1
}
]
})
Note that update query has the format: update(query, update, options) (Check the docs).
When you do { "userName": user_name, "history.id": id } you are telling mongo "Give me all documents where userName is user_name and array history has an id with value id. This return all history array because it belows to the document.
To update an specific object into the array is neccessary to use arrayFilters to tell mongo which object do you want to update. In this case the object where id is equal to 1. You can use as you want to match wit your requirements.
Example here

Finding a nested document and pushing a document into a nested document

So i started learning mongoDB and moongoose today. I have the following Schema:
{
username: {
type : String,
required : true,
unique: true,
trim : true
},
routines : {
type: [
{
_id : mongoose.Schema.Types.ObjectId,
name : String,
todos : [
{
_id : mongoose.Schema.Types.ObjectId,
todo : String,
isCompleted : Boolean
}
]
}
],
}
}
for example:
{
"username": "John",
"routines": [
{
"_id" : 1234, //just for an example assume it to be as 1234
"name" : "Trip plan",
"todos" : [
{
"_id": 1213123,
"todo": "book flight",
"isCompleted" : "false"
}....
]
}......
]
}
what i want to do is, first i would select a document from collection, by using username, then in routines(Array of objects), i want to select a particular routine by id, which would be given by user in request body, now in the selected routine, i want to push into todos array.
For above example, suppose, selecting document with username john, then selecting an object from routines array with _id as 1234, then to its todos i will add a todo.
I have spent almost a day searching about how to do this, while doing this i learnt concepts like arrayFilters, projections. But still couldn't get how to do. Also i read many answers in Stack Overflow, i couldn't grasp much out of them.
PS:I am very new to MongoDB and mongoose, Chances that my question is very silly, and might not be good as per stack overflow standards, I apologize for the same.
You were on the right track, you indeed want to use arrayFilter to achieve this.
Here is a quick example:
// the user you want.
let user = user;
await db.routines.updateOne(
{
username: user.username
},
{
$addToSet: {
"routines.$[elem].todos": newTodo
}
},
{arrayFilters: [{'elem._id': "1234"}]}
);

MongoDB Optional Unique Index

I have a MongoDB schema for users that looks something like this:
{
userId: "some-string",
anonymousId: "some-other-string",
project: {"$oid": "56d06bb6d9f75035956fa7ba"}
}
Users must have either a userId or an anonymousId. As users belong to a project, the model also has a reference called project, which links to the project collection.
Any userId or anonymousId value has to be unique per project, so I created two compound indexes as follows:
db.users.createIndex({ "userId": 1, "project": 1 }, { unique: true })
db.users.createIndex({ "anonymousId": 1, "project": 1 }, { unique: true })
However as not both userId and anonymousId have to be provided but just either one of them, MongoDB throws a duplicate key error for null values (for example if there is a second user with a provided anonymousId but no userId).
I therefore tried to add a sparse: true flag to the compound indexes, but this obviously only works if both fields are empty. I also tried adding the sparse flag only to the fields and not the compound indexes, but this doesn't work either.
To give an example, let's say I have the following three users in the collection:
{ userId: "user1", anonymousId: null, project: {"$oid": "56d06bb6d9f75035956fa7ba"}}
{ userId: "user2", anonymousId: "anonym", project: {"$oid": "56d06bb6d9f75035956fa7ba"}}
{ userId: "user3", anonymousId: "random", project: {"$oid": "56d06bb6d9f75035956fa7ba"}}
The following should be possible:
I want to be able to insert another user {userId: "user4", anonymousId: null} for the same project (without getting a duplicate key error)
However if I try to insert another user with {userId: "user3"} or another user with {anonymousId: "random"} there should be a duplicate key error
How else can I achieve this?
If you are using MongoDB 3.2, you can use unique partial index instead of sparse index.
Partial index is actually recommended over sparse index
Example
db.users.createIndex({ "userId": 1, "project": 1 },
{ unique: true, partialFilterExpression:{
userId: { $exists: true, $gt : { $type : 10 } } } })
db.users.createIndex({ "anonymousId": 1, "project": 1 },
{ unique: true, partialFilterExpression:{
anonymouseId: { $exists: true, $gt : { $type : 10 } } } })
In above example, Unique index will only be created when userId is present and doesn't contain null value. Same holds true to anonymousId too.
Please see https://docs.mongodb.org/manual/core/index-unique/#unique-partial-indexes
index a,c - cannot be sparse as is unique.....
index b,c - cannot be sparse as is unique.....
what about index a,b,c ?
db.benjiman.insert( { userId: "some-string", anonymousId:
"some-other-string", project: {"_oid": "56d06bb6d9f75035956fa7ba"}
})
db.benjiman.insert( { userId: "some-string2", project: {"_oid":
"56d06bb6d9f75035956fa7ba"} })
db.benjiman.insert( { anonymousId: "some-other-string2", project:
{"_oid": "56d06bb6d9f75035956fa7ba"} })
db.benjiman.createIndex({ "userId": 1, "anonymousId": 1, "project": 1 }, { unique: true })