【问题标题】:MongoDB: output 'id' instead of '_id'MongoDB:输出'id'而不是'_id'
【发布时间】:2011-10-25 11:28:53
【问题描述】:

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

【问题讨论】:

  • 对于新读者:下面您将看到多种不同方法。在选择之前阅读它们是明智的,而不是盲目地去接受或大多数选票。干杯!

标签: mongodb node.js mongoose


【解决方案1】:

鉴于您使用的是 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”字段。

【讨论】:

  • 非常好的解决方案 (+1)。我还将添加Schema.set('toObject', { virtuals: true }) 以便在使用console.log(obj) 时能够在输出中看到虚拟。
  • 这会保留 _id 字段。我更喜欢转换解决方案,shakinfree 提供的解决方案对我有用。
  • 'toJson' 仅在转换为 JSON 时。更通用的方法是使用toObjectmongoosejs.com/docs/guide.html#toObject
  • 我放在模型里了,它不运行,我可以把它放在哪里?使用 ExpressJs 放置在 const companyCollection = mongoose.Schema({});
  • 在最新版本的 Mongoose(此时为 5.4.20)中,API 中包含/预建了一个虚拟的 id getter。 mongoosejs.com/docs/guide.html#id
【解决方案2】:

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

默认情况下,Mongoose 会为您的每个模式分配一个 id virtual getter 它将文档 _id 字段转换为字符串,或者在这种情况下 ObjectIds,它的 hexString。如果您不想将 id getter 添加到 您的架构,您可以在架构处通过此选项禁用它 施工时间。 Source

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

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

【讨论】:

  • 这在 v4.0 之前很长时间是正确的,但是 OP 想要的是返回 just id(而不是 _id)。只是告诉 mongoose 包含虚拟 id 会返回两者。
  • 如果您有其他要排除的虚拟对象怎么办?
【解决方案3】:

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

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

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

    return obj;
});

【讨论】:

  • 我对猫鼬真的很陌生,这看起来确实是我想要的。你怎么称呼它为客户端?通常我会这样做,find(),然后取回一个 docs 对象,然后只做 res.send(docs)。所以在这种情况下,我是否在每个文档上调用 res.write(docs[1].toClient()) ?谢谢
  • 这似乎对我不起作用 - 在 Mongoose 中执行此操作的方法是否改变了?
  • 虚拟可能是你想要的。
【解决方案4】:

我用过这个:

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

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

【讨论】:

  • 这个对我有用。 schema 是您创建的每个模型。例如:const UserSchema = new Schema({ stuff }); UserSchema.set("toJSON", { virtuals: true, versionKey: false, transform: function(doc, ret) { delete ret._id; } }); const User = model("user", UserSchema);
  • 如果有人发现这对他们不起作用,请检查您在从数据库中检索文档时是否使用了lean: true 选项。
  • 也可以通过将 versionKey 设置为 false 来禁用文档版本控制。除非您知道自己在做什么,否则不要禁用版本控制。 aaronheckmann.blogspot.com/2012/06/…mongoosejs.com/docs/guide.html#versionKey
  • 我们传递给函数的“doc”是什么?它的内容是什么?
【解决方案5】:

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

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

【讨论】:

    【解决方案6】:
    //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】:

      如果你想使用id 而不是_id 全局 那么你可以在猫鼬对象上设置toJSON 配置(starting from v5.3):

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

      【讨论】:

      • @151291 这是有效的。确保您不使用精益。
      【解决方案8】:

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

      【讨论】:

        【解决方案9】:

        为此,我创建了一个易于使用的plugin,我将其应用于我的所有项目和全球所有架构。它将_id 转换为id 并剥离__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'));
        

        希望这对某人有所帮助。

        【讨论】:

          【解决方案10】:

          用新方法覆盖默认方法toJSON

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

          【讨论】:

            【解决方案11】:

            您还可以在搜索要返回的项目时使用聚合函数。 $project 将允许您创建字段,您可以执行此操作并将其分配给 _id。

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

            【讨论】:

              【解决方案12】:

              如果你使用 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']
                );
              

              【讨论】:

                【解决方案13】:

                覆盖特定模型架构的 toJSONmethod。 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
                  }
                }
                

                【讨论】:

                  【解决方案14】:

                  创建基本架构

                  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 答案的打字稿实现

                  【讨论】:

                    【解决方案15】:

                    还有另一个驱动程序可以做到这一点 http://alexeypetrushin.github.com/mongo-liteconvertId 选项设置为 true。有关详细信息,请参阅“默认值和设置”部分。

                    【讨论】:

                      【解决方案16】:

                      你也可以使用 pre 'save' 钩子:

                      TouSchema.pre('save', function () {      
                        if (this.isNew) {
                          this._doc.id = this._id;      
                        } 
                      }
                      

                      【讨论】:

                        【解决方案17】:
                        JSON.parse(JSON.stringify(doc.toJSON()))
                        

                        【讨论】:

                        • 请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助,质量更高,更有可能吸引投票。
                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 2015-04-16
                        • 2019-10-08
                        • 1970-01-01
                        • 2022-01-17
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多