I am using mongoose (node), what is the best way to output id instead of _id?
I create a toClient() method on my models where I do this. It's also a good place to rename/remove other attributes you don't want to send to the client:
Schema.method('toClient', function() {
var obj = this.toObject();
//Rename fields
obj.id = obj._id;
delete obj._id;
return obj;
});
Given you're using Mongoose, you can use 'virtuals', which are essentially fake fields that Mongoose creates. They're not stored in the DB, they just get populated at run time:
// Duplicate the ID field.
Schema.virtual('id').get(function(){
return this._id.toHexString();
});
// Ensure virtual fields are serialised.
Schema.set('toJSON', {
virtuals: true
});
Any time toJSON is called on the Model you create from this Schema, it will include an 'id' field that matches the _id field Mongo generates. Likewise you can set the behaviour for toObject in the same way.
See:
- http://mongoosejs.com/docs/api.html
- http://mongoosejs.com/docs/guide.html#toJSON
- http://mongoosejs.com/docs/guide.html#toObject
You can abstract this into a BaseSchema all your models then extend/invoke to keep the logic in one place. I wrote the above while creating an Ember/Node/Mongoose app, since Ember really prefers to have an 'id' field to work with.
Schema.set('toObject', { virtuals: true })
to be able to see virtuals in output when using console.log(obj)
. –
Meld toObject
. mongoosejs.com/docs/guide.html#toObject –
Reminisce const companyCollection = mongoose.Schema({});
using ExpressJs –
Astylar id
getter included/prebuilt in the API. mongoosejs.com/docs/guide.html#id –
Sigismondo Cannot read properties of undefined (reading 'toHexString')
–
Ley As of Mongoose v4.0 part of this functionality is supported out of the box. It's no longer required to manually add a virtual id
field as explained by @Pascal Zajac.
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. Source
However, to export this field to JSON, it's still required to enable serialization of virtual fields:
Schema.set('toJSON', {
virtuals: true
});
I used this :
schema.set('toJSON', {
virtuals: true,
versionKey:false,
transform: function (doc, ret) { delete ret._id }
});
I think it would be great if they automatically suppress _id when virtuals is true.
const UserSchema = new Schema({ stuff }); UserSchema.set("toJSON", { virtuals: true, versionKey: false, transform: function(doc, ret) { delete ret._id; } }); const User = model("user", UserSchema);
–
Phalangeal lean: true
option when retrieving your documents from the database. –
Whey I create a toClient() method on my models where I do this. It's also a good place to rename/remove other attributes you don't want to send to the client:
Schema.method('toClient', function() {
var obj = this.toObject();
//Rename fields
obj.id = obj._id;
delete obj._id;
return obj;
});
Here is an alternative version of the answer provided by @user3087827. If you find that schema.options.toJSON
is undefined then you can use:
schema.set('toJSON', {
transform: function (doc, ret, options) {
ret.id = ret._id;
delete ret._id;
delete ret.__v;
}
});
//Transform
Schema.options.toJSON.transform = function (doc, ret, options) {
// remove the _id of every document before returning the result
ret.id = ret._id;
delete ret._id;
delete ret.__v;
}
there is a "Schema.options.toObject.transform" property to do the reverse or you could just setup as a virtual id.
If you want to use id
instead of _id
globally then you can set toJSON
config on mongoose object(starting from v5.3):
mongoose.set('toJSON', {
virtuals: true,
transform: (doc, converted) => {
delete converted._id;
}
});
There is also normalize-mongoose
a simple package that removes _id
and __v
for you.
From something like this:
import mongoose from 'mongoose';
import normalize from 'normalize-mongoose';
const personSchema = mongoose.Schema({ name: String });
personSchema.plugin(normalize);
const Person = mongoose.model('Person', personSchema);
const someone = new Person({ name: 'Abraham' });
const result = someone.toJSON();
console.log(result);
So let's say you have something like this:
{
"_id": "5dff03d3218b91425b9d6fab",
"name": "Abraham",
"__v": 0
}
You will get this output:
{
"id": "5dff03d3218b91425b9d6fab",
"name": "Abraham"
}
Overwrite default method toJSON
by new one:
schema.method('toJSON', function () {
const { __v, _id, ...object } = this.toObject();
object.id = _id;
return object;
});
I created an easy to use plugin for this purpose that I apply for all my projects and to all schema's globally. It converts _id
to id
and strips the __v
parameter as well.
So it converts:
{
"_id": "400e8324a71d4410b9dc3980b5f8cdea",
"__v": 2,
"name": "Item A"
}
To a simpler and cleaner:
{
"id": "400e8324a71d4410b9dc3980b5f8cdea",
"name": "Item A"
}
Usage as a global plugin:
const mongoose = require('mongoose');
mongoose.plugin(require('meanie-mongoose-to-json'));
Or for a specific schema:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const MySchema = new Schema({});
MySchema.plugin(require('meanie-mongoose-to-json'));
Hope this helps someone.
You can also use the aggregate function when searching for items to return. $project will allow you to create fields, which you can do and assign it to _id.
<model>.aggregate([{$project: {_id: 0, id: '$_id'}], (err, res) => {
//
})
Create a base schema
import { Schema } from "mongoose";
export class BaseSchema extends Schema {
constructor(sche: any) {
super(sche);
this.set('toJSON', {
virtuals: true,
transform: (doc, converted) => {
delete converted._id;
}
});
}
}
Now in your mongoose model, use BaseSchema
instead of Schema
import mongoose, { Document} from 'mongoose';
import { BaseSchema } from '../../helpers/mongoose';
const UserSchema = new BaseSchema({
name: String,
age: Number,
});
export interface IUser {
name: String,
age: Number,
}
interface IPlanModel extends IUser, Document { }
export const PlanDoc = mongoose.model<IPlanModel>('User', UserSchema);
Typescript implementation of @Pascal Zajac answer
If you are using lodash to pick the elements you want, this will work for you.
UserSchema.virtual('id').get(function(){
return this._id.toHexString();
});
UserSchema.set('toObject', { virtuals: true })
UserSchema.methods.toJSON = function() {
return _.pick(
this.toObject(),
['id','email','firstName','lastName','username']
);
Override toJSON
method for specific model schema.
https://mongoosejs.com/docs/api.html#schema_Schema-method
YourSchema.methods.toJSON = function () {
return {
id: this._id,
some_field: this.some_field,
created_at: this.createdAt
}
}
this config with nestjs + mongoose
:
@Schema({
versionKey: false, // __v field not saving to db
timestamps: true, // auto add both fields 'createdAt' and 'updatedAt'
toJSON: {
transform(doc, ret, options) {
ret.id = ret._id;
delete ret._id;
},
}
})
saved to database with this fields:
_id: 65b4df698bec4f57043f7bc3
email: "[email protected]"
password :"$argon2id$v"
role: "user"
response to client , id replaced with _id
id: 65b4df698bec4f57043f7bc3 // replaced with _id
email: "[email protected]"
password :"$argon2id$v"
role: "user"
There's another driver that does that http://alexeypetrushin.github.com/mongo-lite set convertId
option to true. See "Defaults & Setting" section for more details.
Mongoose assigns each of your schemas an id virtual getter by default which returns the document's _id field cast to a string, or in the case of ObjectIds, its hexString.
Method 1:
const CartSchema = new Schema({
userId: {
type: String,
required: true
},
products: [{
productId: {
type: String
},
quantity: {
type: Number,
default: 1
},
}]
}, {
toJSON: {
virtuals: true,
transform(doc, ret) {
delete ret.__v
delete ret.password
ret.id = ret._id
delete ret._id
}
}
})
- Change _id to id:
ret.id = ret._id
- Delete _id:
delete ret._id
Method 2:
You can also use pre 'save' hook:
TouSchema.pre('save', function () {
if (this.isNew) {
this._doc.id = this._id;
}
}
JSON.parse(JSON.stringify(doc.toJSON()))
© 2022 - 2024 — McMap. All rights reserved.
Brands.find(query).project({ _id: 0, id: '$_id', name: 1 }).toArray()
– Venosity