Mongoose - Is it possible to access object properties with schema path? - object

As title. There's an object property vote under ActionSchema. I want to access vote.type, but path('vote.type') doesn't work.
ActionSchema = new Schema({
vote: {
type: String
}
});
// TypeError: Cannot call method 'enum' of undefined
ActionSchema.path('vote.type').enum(['upvote', 'downvote']);

The issue is that vote.type isn't the path, vote is. So if you want to modify the vote property, then you want to use ActionSchema.path('vote')
So to add an enum:
ActionSchema.path('vote').enum('upvote', 'downvote');
* Note that you don't pass an array of enum values to this function, you pass the values in as multiple arguments. See the Mongoose documentation for more details.

Related

Nest Js, how to correctly set _id property in your schema

I know it seems quite basic, but I can't seem to find the correct way of setting up the _id field in the Nest.js mongoose schema.
I've attached an image, and was just wondering what the best way to set this property? I get the following error
'SchemaType' only refers to a type, but is being used as a namespace
here.ts(2702)
You don't need to define _id as a prop because it already exists in the Document class. Queries performed against your MusicSupervisorModel will return an object of MusicSupervisorDocument. In case you want to add a field of ObjectId type to your schema you have to do it as follows to preserve casting to ObjectId:
import { Document, SchemaTypes, Types } from 'mongoose';
...
#Prop({ type: SchemaTypes.ObjectId })
yourField: Types.ObjectId
When defining your Mongoose schema in NestJS you really don't have to specify the _id field and all will be fine.
If you want to explicitly define it you have to use following:
...
_id: Schema.Types.ObjectId
...

using spread syntax with Mongoose Document after calling the .save method results in undefined keys

I'm using a Mongoose/MongoDB and I'm getting some odd behaviour when I try to use the spread syntax to return values from a document after I call .save() on it.
// Npc is a Mongoose schema
const npc = new Npc({
...input,
creator: userId
});
const createdNpc = await npc.save();
I have tried using the spead operator, but the name and description keys do not exist.
return {
...createdNpc
creator: userFromId(npc.creator)
}
however when I access those values directly they ARE defined
return {
description: createdNpc.description,
name: createdNpc.name,
creator: userFromId(npc.creator)
};
I've made sure that the spelling of description and name are correct. I've tried logging both {...createdNpc} and {...createdNpc, description: createdNpc.description, name: createdNpc.name}. In the logs I've confirmed that name and description are both not defined (the keys don't exist) inside of {...createdNpc}
I have also tried logging createdNpc and {...createdNpc} and have confirmed that they return different values.
here's createdNpc:
{
_id: 5d8d5c7a04fc40483be74b3b,
name: 'NPC Name',
description: 'My Postman NPC',
creator: 5d8d50e0b5c8a6317541d067,
__v: 0
}
it doesn't actually look like a Mongoose Document at all. I would post the result of {...createdNPC} to show the difference but it's a huge code snippet and I don't want to clutter the question. I'm happy to provide it if it will help!
I'm still very new to MongoDB & Mongoose. Why would using the spread syntax on a Mongoose Document change its value?
I don't think this should be relevant to the question but just in case I'll also mention this is for a graphql resolver.
This is because Mongoose uses getters for all of its attributes. Before you use the spread operator, call createdNpc.toObject() to get a normal Object.

Missing Mongoose Schema Property Still Being Returned

Given a schema that looks like this:
var schema = new mongoose.Schema({ name: 'string', size: 'string' });
And the database contains "name" for all objects in the collection. But then I change it and remove name
var schema = new mongoose.Schema({ size: 'string' });
And then I do a find on it:
schema.find({}).exec().then( (objs) => {
// objs[0].name still exists
I thought that if the schema didn't specify a property then it wouldn't exist on the found objects. Is this not the case? Is the only way to remove a property, to actually remove it from the object in mongo?
Quoting from the original maintainer, Aaron Heckmann:
[M]ongoose "plays nice" with existing data in the db, not deleting it unless you tell it to.
[D]eleting the property would work if mongoose was able to hook into that even but alas it cannot. [H]owever you can completely remove the property from your document by setting the values to undefined which will trigger an $unset.
Source: Google Groups
Basically Mongoose attempts to be non-destructive to existing data. If a property is no longer needed you could run an update on the database to unset the value which would remove the property from every document in the collection.

Mongoose keeps giving both _id and id with same value

I have some Mongoose schemas, whose certain fields need getter and setters.
For that, i've set the following:
MySchema.set('toObject',{getters:true});
MySchema.set('toJSON',{getters:true});
Whenever I send/read the result of MySchema.find(), it gives me both _id and id fields, which have same value.
I think thats a virtual field (correct me if i'm wrong here)
How do i stop this? I don't want to process through each and every object and remove the field.
Documented here:
Mongoose assigns each of your schemas an id virtual getter by default which returns the documents _id field cast to a string, or in the case of ObjectIds, its hexString. If you don't want an id getter added to your schema, you may disable it passing this option at schema construction time.
Just set the id field to false while creating the schema:
var schema = new Schema({ name: String }, { id: false });

Add a new attribute to existing json object in node.js

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

Resources