Mongoose: Преобразование всех ObjectId в строку с помощью метода Document.toObject()?

Созданный на 25 мар. 2015  ·  24Комментарии  ·  Источник: Automattic/mongoose

Поскольку я обнаружил, что _id в документе все еще является ObjectId после toObject()

Есть ли способ добиться этого?

Самый полезный комментарий

Эта особенность Mongo действительно вызывает сожаление

Все 24 Комментарий

У меня такой же баг. И toJSON() , и toObject() не преобразуют экземпляры ObjectId строку.

Сейчас это предусмотрено дизайном, потому что технически ObjectId не являются строками. Внезапно мне приходит в голову единственный способ, которым я могу думать, это JSON.parse(JSON.stringify(doc)); Каков ваш вариант использования для упорядочения всех идентификаторов объектов?

Итак, функция toJSON() не преобразует объект в строку JSON? _id и дата - это не строка, а объект?

кстати, в чем разница между toObject() и toJSON() ?
Спасибо!

Да, дата должна быть датой, а не строкой, после toJSON() + toObject() .

toJSON() и toObject() по существу идентичны, единственное отличие состоит в том, что когда вы делаете JSON.stringify(doc) , JavaScript ищет функцию toJSON() в документе и использует ее для преобразования объект. Таким образом, причиной toJSON() является синтаксический сахар для JSON.stringify() .

@vkarpov15 Извините за комментарий к закрытой проблеме, но это показалось наиболее подходящим местом для публикации, поскольку оно напрямую связано с этой проблемой.

Я пытаюсь глубоко сравнить два документа мангуста, чтобы получить объект различий между ними.
Однако ObjectID нельзя сравнивать напрямую, потому что они всегда будут отличаться, даже если они содержат точно такие же идентификаторы.

Единственный способ, которым я смог это сделать до сих пор, это сделать это:

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

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

Это кажется дорогим способом получить разницу между объектами.
Знаете ли вы лучший способ надежно сравнить документы мангуста?

Не уверен, как работает deep diff, но могут возникнуть проблемы с ObjectIds mongodb. Попробуйте преобразовать _id и другие поля objectid в строки. Или просто используйте глубокую проверку равенства lodash, я думаю, что она работает с ObjectIds

@vkarpov15 deep diff использует lodash для проверки на равенство, поэтому, к сожалению, это не сработает:
https://github.com/rbs392/object-deep-diff/blob/master/index.js

Преобразование всех ObjectId в строки будет работать, но, поскольку объекты могут содержать массивы и/или другие вложенные объекты, это также становится довольно дорогой задачей..:/

Итак, вот еще один вопрос: вы используете deep-diff для 2 документов мангуста или 2 документов, которые являются результатом toObject() ? Последнее должно работать, первое не очень.

@ vkarpov15 обычно это 1 документ мангуста (преобразованный в объект javascript с помощью .toObject) и один обычный объект javascript.
Причина в том, что мне нужно сравнить данные, поступающие от клиента, с данными, которые уже есть в базе данных.
Таким образом, данные, поступающие от клиента, уже имеют преобразованный ObjectID, а данные, поступающие из базы данных, — нет.
Но поскольку я выполняю эту глубокую проверку различий в плагине мангуста, мне нужно быть абсолютно уверенным, что оба документа созданы одинаково, поэтому мне нужно запустить JSON.parse(JSON.stringify(doc.toObject()) ) в обоих документах.

Да, в этом случае вам нужно будет сделать JSON.parse(JSON.stringify()) , это самый простой способ преобразовать все идентификаторы объектов в строки.

Для меня JSON.parse(JSON.stringify()) требовал слишком больших вычислительных ресурсов, поэтому мне пришлось создать эту перфомансную библиотеку .

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 (массив ObjectId)?

@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()), это самый простой способ преобразовать все идентификаторы объектов в строки.

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

тлдр; JSON.parse(JSON.stringify()) — это синхронная блокирующая задача, которая может вызвать серьезные узкие места. Это не должно быть принятым/предлагаемым решением этой проблемы...

Вы также должны уметь делать mongoose.Types.ObjectId.prototype.toJSON = function() { return this.toString(); . Но даже в этой статье говорится, что JSON.parse(JSON.stringify) — один из самых быстрых способов сделать глубокое клонирование, их проблема заключалась в том, что они многократно выполняли излишнее глубокое клонирование.

Итак, вот и 2019 год.
Есть ли у нас хороший, чистый и очевидный способ получить шестнадцатеричную строку из каждого экземпляра ObjectId на объекте?

@gitowec

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

См.: http://thecodebarbarian.com/whats-new-in-mongoose-54-global-schematype-configuration.html#schematype -getters

@ vkarpov15 похоже, что это не решение при использовании «бережливого производства».
Поэтому, если желаемый результат состоит в том, чтобы вернуть простой объект 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 рейтинги