I want to be able to add a new object property to an object in a document stored in a mongodb database where the model schema does not include that property. I've seen all sorts of examples on google and none of them seem to work so I want to ask this question myself and get some direct answers.
For example take this scheme
const MapSchema = new mongoose.Schema({
name:{
type: String
}
})
const ListMap = mongoose.model("listmap", MapSchema);
Now I want to add a new property to it using its id
model.ListMap.findByIdAndUpdate(_id, {newprop:"whatever");
model.ListMap.findByIdAndUpdate(_id, {name:"test");
Using those two commands, I can add name:"test" to it but I can not add newprop:"whatever" to it. What I want to do is be able to add a new property without having to declare it in the schema first. I know this seems like it has been asked before but I've googled it all and I don't believe anyone has answered it. They either didn't understand the question or their code doesn't actually work.
Also bonus question, why does mongodb always add an s to collection names? like the above would show up in collection "listmaps", assuming I used .create() to add the first object.
For your first question, you can not add a property to your schema without declaring it first.
you can define a generic property like this:
const MapSchema = new mongoose.Schema({
property:{
title: String,
value: String
}
})
const ListMap = mongoose.model("listmap", MapSchema);
and for your second question you can refer to this answer:
Why does mongoose always add an s to the end of my collection name
-------SOLVED-------------
I am adding this here for others because it was extremely difficult for me to google this. This answer is from another stackexchange link
How to add a new key:value pair to existing sub object of a mongoDB document
based on this, this is how to do what I proposed earlier
const commentMapSchema = new mongoose.Schema({
List:{}
})
const CommentsMap = mongoose.model("commentmap", commentMapSchema);
const update = {$set: {["List."+"test2"] : "data2"}};
CommentsMap.findByIdAndUpdate(id, update);
First you need to declare the property in the schema. This property can hold more properties exactly like how it works with javascript objects. Then use the update method with mongoose with the query that combines the property name with a new property via dot notation. However when adding a property this way, the key must be a string. This works exactly like it does in javascript. You can just create a new name and it'll add to the object properties.
I hope this helps anyone else who landed here.
I am using graphql to get some data from mongodb database. So, I was making an api which on running saves data in main collection but also saves data in some other collection with a couple of more data. I was trying to delete _id from the data that I get on saving on main collection but it's not working and I can't figure out why.
Here's what's happening
const data = await User.getResolver('updateById').resolve({ //default resolver from graphql-compose library to update a record. Returns the whole document in record //
args: {...rp.args}
})
const version = '4'
const NewObject = _.cloneDeep(data.record);
NewObject.version = version;
NewObject.oldId = data._id;
_.unset(NewObject, '_id'); //this doesn't work neither does delete NewObject._id//
console.log('new obj is', NewObject, version, NewObject._id, _.unset(NewObject, '_id')); //prints _id and surprisingly the unset in console.log is returning true that means it is successfully deleting the property//
I am very confused to what I am doing wrong.
Edit: Sorry should have mentioned, but according to lodash docs _.unset returns true if it successfully deletes a property.
Turn's out mongoDb makes _id as a Non configurable property. So, to do this I had to make use of toObject() method to make an editable copy of my object.
const NewObject = _.cloneDeep(data.record).toObject();
With this I was able to delete _id.
Alternatively _.omit of lodash also works.
Which is a better way of saving a document so that it may not cause any error while using other methods of mongoose such as findOneAndUpdate()?
const doc = new Doc();
// Some lines of the code
doc.save(...)
.then(...)
.catch(...);
OR,
const doc = {};
//Some lines of code
Doc(doc).save()
.then(...)
.catch(...)
Use doc.save() when creating a new document. And use findOneAndUpdate() when you are updating an existing document. They both don't cause any interference with each other.
I am using Node.js with mongoose together with Typescript. And based on SO threads like this queries should work with my function as well:
let conditions = {};
conditions['belongsToRestaurant'] = dto.restId;
conditions['belongsToRestaurant']
await Order.findOne({conditions}).then((doc) => {
console.log('doc');
console.log(doc);
})
The console always logs the proper value for "restId", and always null for "doc".
I have tried every single variation I could think of. I created an object with a constructor, created an object with a set property, tried with classes nothing worked. I tried using mongoose types, such as:
conditions['consumerName'] = new mongoose.Schema.Types.String("asasd");
conditions['belongsToRestaurant'] = mongoose.Types.ObjectId(dto.restId);
Nothing has worked so far. Thx for reading and help in advance!
Sidenote: Keep in mind these fields I am referencing are not in array, or in a subdocument or anything of that nature. And work completely fine when I am not using objects to update.
Just a tiny mistake of wrapping the condition object inside an object.
Removing the wrapping curly braces from the findOne function will fix the problem.
const conditions = {};
conditions.belongsToRestaurant = dto.restId;
await Order.findOne(conditions)
.then((doc) => {
console.log('doc');
console.log(doc);
});
I have an object like this
==================records=========={ Id: 5114a3c21203e0d811000088,
userId: 'test',
sUserId: test,
userName: 'test',
url: 'test',
Title: 'test'
}
I need to add a new field Name : 'test' to the above record, I tried giving records.Name = name, it didn't work.
Helps please
Thanks,
Prats
I am assuming you are trying to add a property to a returned Mongoose Document to reuse it somewhere else. Documents returned by Mongoose are not JSON objects directly, you'll need to convert them to an object to add properties to them. The following should work:
//... record is a mongoose Document
var r = record.toObject();
r.Name = 'test';
console.log("Record ",r);
Those finding this problem, OP mentioned in a comment below the original question that the solution for this problem is:
records.set('Name', 'test')
This adds a new attribute called Name having value test.
Just use,
var convertedJSON = JSON.parse(JSON.stringify(mongooseReturnedDocument);
and Then,
convertedJSON.newProperty = 'Hello!'
'Hello!' can be anything, a number, a object or JSON Object Literal.
Cheers! :)
I experienced a similar problem, and hope that my hours of existential frustration help others in the same situation. My inclination was to believe that documents returned via Mongoose are read-only. This is actually not true.
However, you cannot assign a property to your document that is not also in your Schema.
So, unless your schema has the following:
{
Name: {String}
}
you will be constantly frustrated by trying to assign Name to your document.
Now, there are workarounds in the answers above that also worked for me, but they do not get to the root of the problem:
myDocument.toObject();
JSON.parse(JSON.stringify(myDocument);
These will work, but in my opinion they just hide the problem. The real issue is that Mongoose is smarter than we realized and is enforcing your schema, as it should.
You could also use the lean() method, e.g. const users = await Users.find().lean().exec()
From the mongoose documentation:
Documents returned from queries with the lean option enabled are plain
javascript objects, not MongooseDocuments. They have no save method,
getters/setters or other Mongoose magic applied
My variant.
If schema defined with {strict:false} you can simply add new property by
recorcd.newProp = 'newvalue';
If schema defined with {strict:true} you can either convert Mongoose object to object as mentioned earlier or use command
record.set('newProp','newValue',{strict:false})
See http://mongoosejs.com/docs/api.html#document_Document-schema
If you have loaded this object into records, both records.Name = "test" or records['Name'] = "test" will work. You have either not loaded the object correctly, or are inserting an undefined value into it.
To test: add console.log(records.userId), this should print 'test' to the terminal.
Also add console.log(name). If you get ReferenceError: name is not defined, you obviously cannot do: records.Name = name