MongoDB: 输出‘ id’而不是‘_id’

我正在使用 monose (node) ,输出 id 而不是 _ id 的最佳方式是什么?

90410 次浏览

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

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.

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:

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.

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

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

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

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.

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) => {
//
})

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']
);

Overwrite default method toJSON by new one:

schema.method('toJSON', function () {
const { __v, _id, ...object } = this.toObject();
object.id = _id;
return object;
});

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"
}

Override toJSONmethod 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
}
}

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

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

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()))

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.

https://mongoosejs.com/docs/guide.html