Mongoose keeps giving both _id and id with same value - node.js

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 });

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
...

Mongoose: convert _id types in existing collection

I have an existing mongoose collection with using the default ObjectID type for _id.
I want to migrate this collection to use a UUID for the _id, ideally without a special migration step.
My new schema makes use of the package mongoose-uuid4:
var uuidv4 = require('uuid/v4');
require('mongoose-uuid4')(mongoose);
const schema = new mongoose.Schema({
_id: { type: mongoose.Types.UUID, default: uuidv4 },
...
});
const Model = mongoose.model('Model', schema);
My theory here is that my existing ObjectIDs could be zero-padded to be valid UUID objects, so I should be able to write my access methods so I can find by either a short ObjectID or a full UUID.
If I do a Model.find({}) on this collection, the documents come back with no _id fields, but I do get an exception thrown that says it couldn't cast the id value to a UUID:
ValidationError: <Model> validation failed: undefined: Could not cast 6132ba2d6474631eeb038a9b to UUID.
So this makes me think there's a place where I can insert some code to do a type conversion to make this work, because some part of the mongoose stack tried to do this conversion, but didn't know how to.
My first preference is an on-the-fly way of allowing existing _id fields to get upgraded, but I am also ok with a one-time 'fixup' pass through the collection to upgrade fields.
Any suggestions are appreciated.

Non-existing field in Mongodb document appears in mongoose findById() result

I'm somewhat new in what is related to Mongoose and I came to this behaviour I consider as strange. The document returned by Mongoose has fields that are not present in the actual MongoDb document, and seem to be added by Mongoose based on the schema.
I use a schema similar to this (this one is simplified) :
const ProfessionalSchema = new mongoose.Schema({
product: {
details: [{
_id: false,
id: String, // UUID
name: String,
prestations: [{
_id: false,
id: String, // UUID
name: String,
price: Number,
}],
}],
},
[...]
My document as shown in Mongodb with mongo CLI utility doesn't have a product field.
What I don't understand is why the result of Professional.findById().exec() returns a document with a product:{details[]} field. I expect not to have that field in the Mongoose returned result, since it is not present in the original MongoDb document.
The Mongoose documentation found https://mongoosejs.com/docs/guide.html (Schema and Model paragraph) didn't help.
My business logic would require that field not to be present, instead of being forced by the schema. Is this achievable ?
Try taking a look at the default option. You could e.g. default your product to null and then, in your business logic, handle the "product is null" case rather than the "product field does not exist" case.
As for why this is happening, it's because you're dealing with a schema. If the field doesn't exist on the document, it's going to be auto-populated. The whole point of a schema is to ensure consistency of your document structure.

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.

Using 'generic' virtual for mongoose schema

I want to convert _id variable as id.
So i want to add virtual 'id' field to all the schema i am going to create, that will return the value of '_id' whenever i access 'id' field of the model.
from the documentation http://mongoosejs.com/docs/2.7.x/docs/virtuals.html
i found that, first i have to create schema then apply the virtual 'id' field individually.
I want to simply add virtual field to the base mongoose.Schema and then whenever i will create a new schema, that all will have virtual field without any manual effort on each of the individual schema.
EDIT :
i am also using Backbone.Model and i have created an 'id' field for each model. If i get the simply use id in the front end codes, i get the error that id field not exists. BUT when i set idAttribute as '_id' to each model then everything goes OK. That means backbone model want to have _id, and the reason behind mongoose schema have _id not id. So can i interpret that, mongoose does not automatically add virtual id mapped to _id? Correct me if i am wrong.
For backbone, "id" is it's default idAttribute name, so just don't add any code there and everything will work as intended.
For mongoose, the answer boils down to "it's complicated", but the main points are:
By default mongoose will give each schema a virtual called "id" which will be the document's _id as a string
However, by default .toJSON doesn't include virtuals, so when you send a mongoose document to backbone in the browser, it gets just "_id" and not "id"
to quickly get a JSON representation including the virtuals, use myModelInstance.toJSON({virtuals: true}). You'll get both "_id" and "id"
You need to read up on the transform options for toObject and toJSON to get a full picture of what you can do and how, but the gist is (based on examples straight from the docs)
// specify the transform schema option
if (!schema.options.toJSON) schema.options.toJSON = {};
schema.options.toJSON.transform = function (doc, ret, options) {
// remove the _id of every document before returning the result
delete ret._id;
}
schema.options.toJSON.virtuals = true;

Resources