MongoDB:输出“ id”而不是“ _id”


73

我正在使用猫鼬(节点),输出id而不是_id的最佳方法是什么?


15
对于新读者:在下面,您将看到多种不同的方法。明智的做法是在选择之前先阅读所有内容,而不是盲目地接受已接受或多数票。干杯!
sshow

Answers:


37

我在执行此操作的模型上创建toClient()方法。这也是重命名/删除您不想发送给客户端的其他属性的好地方:

Schema.method('toClient', function() {
    var obj = this.toObject();

    //Rename fields
    obj.id = obj._id;
    delete obj._id;

    return obj;
});

2
我真的是猫鼬的新手,这确实像我想要的。您如何称其为“客户”?通常,我会执行find()并获取一个docs对象,然后执行res.send(docs)。因此,在这种情况下,我是否要在每个文档上调用res.write(docs [1] .toClient())?谢谢
约翰尼

1
这似乎对我现在不起作用-在Mongoose中执行此操作的方法是否已更改?
outside2344

5
虚拟机可能就是您想要的。
Leonidas

111

假设您使用的是Mongoose,则可以使用“虚拟”,这实际上是Mongoose创建的伪字段。它们没有存储在数据库中,只是在运行时填充:

// Duplicate the ID field.
Schema.virtual('id').get(function(){
    return this._id.toHexString();
});

// Ensure virtual fields are serialised.
Schema.set('toJSON', {
    virtuals: true
});

每当在您从此模式创建的模型上调用toJSON时,它将包含一个与Mongo生成的_id字段匹配的'id'字段。同样,您可以以相同的方式设置toObject的行为。

看到:

您可以将其抽象为所有模型的BaseSchema,然后进行扩展/调用以将逻辑保持在一个位置。我在创建Ember / Node / Mongoose应用程序时写了以上内容,因为Ember确实更喜欢使用“ id”字段。


5
很好的解决方案(+1)。我还要补充一点Schema.set('toObject', { virtuals: true }),以便在使用时能够在输出中看到虚拟console.log(obj)
汤姆(Tom)

5
这将保留_id字段。我更喜欢转换解决方案,shakinfree提供的解决方案为我工作。
Peter Hedberg 2014年

3
仅在转换为JSON时才使用“ toJson”。更通用的方法是使用toObjectmongoosejs.com/docs/guide.html#toObject
Dave Jensen

我将其放置在模型中,它无法运行,我可以在哪里放置它?const companyCollection = mongoose.Schema({});使用ExpressJs放置在此文件下
151291 '19

在最新版本的Mongoose(目前为5.​​4.20)id中,API中包含/预构建了一个虚拟吸气剂。mongoosejs.com/docs/guide.html#id
David Ferreira,

40

从Mongoose v4.0开始,此功能的一部分已开箱即用id如@Pascal Zajac所述,不再需要手动添加虚拟字段。

Mongoose默认情况下为您的每个模式分配一个id虚拟getter,该属性将文档_id字段强制转换为字符串,对于ObjectIds,则返回其hexString。如果您不希望在架构中添加id getter,则可以在架构构建时通过此选项将其禁用。资源

但是,要将此字段导出JSON,仍然需要启用虚拟字段的序列化:

Schema.set('toJSON', {
    virtuals: true
});

4
在v4.0之前很久就是如此,但是OP希望返回的只是id(而不是_id)。只是告诉猫鼬包括虚拟ID都会返回两者。
neverfox

如果您要排除其他虚拟机怎么办?
亚历克斯·麦克米伦

30

我用这个:

schema.set('toJSON', {
  virtuals: true,
  versionKey:false,
  transform: function (doc, ret) {   delete ret._id  }
});

我认为如果在virtuals为true时自动抑制_id会很棒。


这个为我工作。模式是您创建的每个模型的位置。例如: const UserSchema = new Schema({ stuff }); UserSchema.set("toJSON", { virtuals: true, versionKey: false, transform: function(doc, ret) { delete ret._id; } }); const User = model("user", UserSchema);
user3152459 '20

如果有人发现这种方法不能立即为他们解决,请lean: true在从数据库中检索文档时检查您是否没有使用该选项。
–coatesap

也可以通过将versionKey设置为false来禁用文档版本控制。除非您知道自己在做什么,否则请勿禁用版本控制。aaronheckmann.blogspot.com/2012/06/... mongoosejs.com/docs/guide.html#versionKey
ET-CS

28

这是@ user3087827提供的答案的替代版本。如果发现schema.options.toJSON未定义,则可以使用:

schema.set('toJSON', {
     transform: function (doc, ret, options) {
         ret.id = ret._id;
         delete ret._id;
         delete ret.__v;
     }
}); 

25
//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;
}

有一个“ Schema.options.toObject.transform”属性可以执行相反操作,也可以将其设置为虚拟ID。


7

为此,我创建了一个易于使用的插件,将其应用于所有项目以及全球所有架构。它也将转换_idid并剥离__v参数。

因此它转换为:

{
  "_id": "400e8324a71d4410b9dc3980b5f8cdea",
  "__v": 2,
  "name": "Item A"
}

为了更简单,更清洁:

{
  "id": "400e8324a71d4410b9dc3980b5f8cdea",
  "name": "Item A"
}

用作全局插件:

const mongoose = require('mongoose');
mongoose.plugin(require('meanie-mongoose-to-json'));

或针对特定架构:

const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const MySchema = new Schema({});
MySchema.plugin(require('meanie-mongoose-to-json'));

希望这对某人有帮助。


5

toJSON用新方法覆盖默认方法:

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

5

如果要使用id而不是_id 全局使用,则可以toJSONmongoose对象上设置config(从v5.3开始):

mongoose.set('toJSON', {
  virtuals: true,
  transform: (doc, converted) => {
    delete converted._id;
  }
});

3

还有normalize-mongoose一个简单的包,消除_id__v为您服务。

从这样的事情:

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

因此,假设您有这样的事情:

{
  "_id": "5dff03d3218b91425b9d6fab",
  "name": "Abraham",
  "__v": 0
}

您将获得以下输出:

{
  "id": "5dff03d3218b91425b9d6fab",
  "name": "Abraham"
}

2

搜索要返回的项目时,也可以使用聚合函数。$ project将允许您创建字段,然后可以将其分配给_id。

<model>.aggregate([{$project: {_id: 0, id: '$_id'}], (err, res) => {
 // 
})

1

如果您使用lodash来选择所需的元素,这将为您工作。

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



0

创建一个基础架构

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

现在在您的猫鼬模型中,使用BaseSchema代替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);

@Pascal Zajac答案的打字稿实现

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.