Mongoose: 使用 Document.toObject() 方法将所有 ObjectIds 转换为字符串?

创建于 2015-03-25  ·  24评论  ·  资料来源: Automattic/mongoose

我发现文档中的_id在 toObject() 之后仍然是一个 ObjectId

有没有办法做到这一点?

最有用的评论

Mongo的这个特性真的很遗憾

所有24条评论

我有同样的错误。 toJSON()toObject()都不会对ObjectId实例进行字符串化。

现在这是设计使然,因为 ObjectId 在技术上不是字符串。 在我的脑海中,我能想到的唯一方法是JSON.parse(JSON.stringify(doc));您对所有对象 ID 进行字符串化的用例是什么?

那么,函数toJSON()不会将对象转换为 JSON 字符串吗? _id 和日期不是字符串而是对象?

顺便问一下, toObject()toJSON()有什么区别?
谢谢!

是的,在toJSON() + toObject()之后,日期仍然应该是一个日期,而不是一个字符串。

toJSON()toObject()本质上是相同的,唯一的区别是当你做JSON.stringify(doc) JavaScript 在 doc 上查找toJSON()函数并使用它来转换目的。 所以toJSON() JSON.stringify()语法糖。

@vkarpov15很抱歉对已关闭的问题发表评论,但它似乎是最相关的发布位置,因为它与此问题直接相关。

我正在尝试深入比较两个猫鼬文档以获取它们之间更改的差异对象。
然而,ObjectID 似乎不能直接比较,因为它们总是以差异结尾,即使它们包含完全相同的 id。

到目前为止,我能够做到的唯一方法就是这样做:

var objectdiff = require('object-deep-diff');

var diffresult = objectdiff(
  JSON.parse(JSON.stringify(doc1.toObject())),
  JSON.parse(JSON.stringify(doc2.toObject()))
);

这似乎是一种获取对象之间差异的昂贵方法。
您知道可靠比较猫鼬文档的更好方法吗?

不确定深度差异的工作原理,但它可能会遇到 mongodb ObjectIds 的一些问题。 尝试将 _id 和其他 objectid 字段转换为字符串。 或者只是使用 lodash 的深度相等检查,我认为可以使用 ObjectIds

@vkarpov15 deep diff 使用 lodash 进行相等性检查,所以很遗憾这不起作用:
https://github.com/rbs392/object-deep-diff/blob/master/index.js

将所有 ObjectId 转换为字符串是可行的,但由于对象可以包含数组和/或其他嵌套对象,这也成为一项非常昂贵的任务......:/

所以这是另一个问题,您是在 2 个 mongoose 文档还是 2 个toObject()结果的文档上使用深度差异? 后者应该工作,前者没有那么多。

@vkarpov15通常是 1 个 mongoose 文档(使用 .toObject 转换为 javscript 对象)和一个常规 javascript 对象。
原因是我需要将来自客户端的数据与数据库中已有的数据进行比较。
因此,来自客户端的数据已经转换了 ObjectID,但来自数据库的数据没有。
但由于我在 mongoose 插件中进行这种深度差异检查,我需要绝对确保两个文档的构造相同,所以这就是为什么我必须运行 JSON.parse(JSON.stringify(doc.toObject()) ) 在两个文档上。

是的,在这种情况下,您将需要执行JSON.parse(JSON.stringify()) ,这是将所有对象 ID 转换为字符串的最简单方法。

JSON.parse(JSON.stringify())对我来说计算量太大,所以我不得不创建这个 perf-thinking lib

var transformProps = require('transform-props');

function castToString(arg) {
    return String(arg);
}

var doc = new MongooseModel({ subDoc: { foo: 'bar' }});
var docObj = doc.toObject();

transformProps(docObj, castToString, '_id');

console.log(typeof docObj._id); // 'string'
console.log(typeof docObj.subDoc._id); // 'string'

Mongo的这个特性真的很遗憾

@ZacharyRSmith那么其他道具呢,例如。 author_id(ObjectId 指的是用户模型)/author_ids(ObjectIds 数组)?

@flight9您可以告诉 transformProps() 查找多个键。 在这里看到这个测试: https ://github.com/ZacharyRSmith/transform-props/blob/master/index.test.js#L67

我相信你可以得到你想要的:

function myToString(val) {
  if (Array.isArray(val)) {
    return val.map(item => String(item));
  }
  return String(val);
}

transformProps(obj, myToString, ['author_id', 'author_ids']);

@ZacharyRSmith感谢您的解决方案,太好了!

我想我错过了一件重要的事情:我事先不知道哪些字段是 ObjectId,因为我正在编写的工具应该应用于我们项目中的所有模型,这些模型可能有多个 ObjectId 字段或没有,以及它的字段名称是不确定的。
所以经过几个小时的尝试,我有我的解决方案:

const ObjectID = require('mongodb').ObjectID;

/**
 * Convert ObjectId field values inside an object to String type values
 * (includes array of ObjectIds and nested ObjectId fields)
 * <strong i="9">@param</strong> obj Object - The Object to be converted.
 * <strong i="10">@return</strong> none
 */
function objectIdtoString(obj) {
  for(let k in obj) {
    let v = obj[k];
    if(typeof v == 'object') {
      if(k.endsWith('_id') && v instanceof ObjectID) {
        obj[k] = v.toString();
      }
      else if(
        k.endsWith('_ids') && Array.isArray(v) &&
        v.length > 0 && v[0] instanceof ObjectID
      ) {
        let vs = [];
        for(let iv of v) {
          vs.push(iv.toString());
        }
        obj[k] = vs;
      }
      else {
        objectIdtoString(v);
      }
    }
  }
}

// Call example
objectIdtoString(obj):

@vkarpov15

是的,在这种情况下,您将需要执行 JSON.parse(JSON.stringify()),这是将所有对象 ID 转换为字符串的最简单方法。

https://medium.com/ft-product-technology/this-one-line-of-javascript-made-ft-com-10-times-slower-5afb02bfd93f

tldr; JSON.parse(JSON.stringify())是一个同步的阻塞任务,可能会导致严重的瓶颈。 这不应该是这个问题的接受/建议的解决方案......

你也应该能够做到mongoose.Types.ObjectId.prototype.toJSON = function() { return this.toString(); 。 但即使那篇文章说,JSON.parse(JSON.stringify) 是进行深度克隆的更快方法之一,他们的问题是他们重复不必要的深度克隆

所以,这里是 2019 年。
我们是否还有从对象上的每个 ObjectId 实例获取十六进制字符串的好方法?

@gitowiec

mongoose.ObjectId.get(v => v.toString());

请参阅: http ://thecodebarbarian.com/whats-new-in-mongoose-54-global-schematype-configuration.html#schematype -getters

@vkarpov15看起来这不是使用“精益”时的解决方案。
因此,如果想要的结果是返回一个带有字符串 objectIds 的普通 json 对象,那么实现这一点的最有效方法似乎是仍然使用JSON.parse(JSON.stringify())lean选项。

或者可能是一个精益插件: https ://www.npmjs.com/package/mongoose-lean-objectid-string

@nhitchins正确,您必须使用像 mongoose -lean-getters这样的插件。

@vkarpov15这也应该与鉴别器模式一起使用吗? 我有一个基本架构,我从中创建变体。 我尝试在基本架构上设置吸气剂。 我使用了 lean() 并使用了 mongoose-lean-getters,但我无法让它工作。

@pwrnrd你能打开一个新问题并遵循问题模板吗? 它应该与鉴别器模式一起正常工作。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

ghost picture ghost  ·  3评论

Igorpollo picture Igorpollo  ·  3评论

ArThoX picture ArThoX  ·  3评论

adamreisnz picture adamreisnz  ·  3评论

lukasz-zak picture lukasz-zak  ·  3评论