Mongoose: Mengubah semua ObjectIds menjadi string dengan menggunakan metode Document.toObject()?

Dibuat pada 25 Mar 2015  ·  24Komentar  ·  Sumber: Automattic/mongoose

Ketika saya menemukan bahwa _id dalam dokumen masih merupakan ObjectId setelah toObject()

Apakah ada cara untuk mencapai ini?

help

Komentar yang paling membantu

Fitur Mongo ini sangat disesalkan

Semua 24 komentar

Saya punya bug yang sama. Baik toJSON() dan toObject() tidak membuat string dari instance ObjectId .

Ini dirancang sekarang, karena ObjectIds secara teknis bukanlah string. Dari atas kepala saya, satu-satunya cara yang dapat saya pikirkan adalah dengan JSON.parse(JSON.stringify(doc)); Apa kasus penggunaan Anda untuk merangkai semua id objek?

jadi, fungsi toJSON() tidak mengonversi objek menjadi string JSON? _id dan tanggal bukan string tetapi objek?

omong-omong, apa perbedaan antara toObject() dan toJSON() ?
Terima kasih!

Ya tanggal harus tetap tanggal, bukan string, setelah toJSON() + toObject() .

toJSON() dan toObject() pada dasarnya identik, satu-satunya perbedaan adalah ketika Anda melakukan JSON.stringify(doc) JavaScript mencari fungsi toJSON() pada dokumen dan menggunakannya untuk mengonversi obyek. Jadi alasan toJSON() adalah gula sintaksis untuk JSON.stringify() .

@vkarpov15 Maaf telah mengomentari masalah tertutup, tetapi tampaknya tempat yang paling relevan untuk memposting, karena ini terkait langsung dengan masalah ini.

Saya mencoba membandingkan dua dokumen luwak untuk mendapatkan objek berbeda dari perubahan di antara mereka.
Namun ObjectID, sepertinya tidak dapat dibandingkan secara langsung, karena mereka akan selalu berakhir dengan diff, bahkan jika mereka berisi id yang sama persis.

Satu-satunya cara saya bisa melakukannya sejauh ini, adalah melakukan ini:

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

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

Itu sepertinya cara yang mahal untuk mendapatkan perbedaan antara objek.
Apakah Anda tahu cara yang lebih baik untuk membandingkan dokumen luwak secara andal?

Tidak yakin seberapa dalam diff bekerja tetapi mungkin mengalami beberapa masalah dengan mongodb ObjectIds. Coba ubah _id dan bidang objectid lainnya menjadi string. Atau cukup gunakan pemeriksaan kesetaraan mendalam lodash, saya pikir itu berfungsi dengan ObjectIds

@vkarpov15 deep diff menggunakan lodash untuk pemeriksaan kesetaraan, jadi sayangnya itu tidak akan berhasil:
https://github.com/rbs392/object-deep-diff/blob/master/index.js

Mengonversi semua ObjectId ke string akan berhasil, tetapi karena objek dapat berisi array dan/atau objek bersarang lainnya, itu juga menjadi tugas yang cukup mahal untuk dilakukan.. :/

Nah ini pertanyaan lagi, apakah anda menggunakan deep-diff pada 2 dokumen luwak atau 2 dokumen hasil toObject() ? Yang terakhir harus bekerja, yang pertama tidak begitu banyak.

@vkarpov15 biasanya 1 dokumen luwak (dikonversi menjadi objek javscript dengan .toObject) dan satu objek javascript biasa.
Alasannya karena saya perlu membandingkan data yang berasal dari klien, dengan data yang sudah ada di database.
Jadi, data yang berasal dari klien sudah memiliki ObjectID yang dikonversi, tetapi data yang berasal dari database belum.
Tetapi karena saya melakukan pemeriksaan perbedaan-dalam ini di plugin luwak, saya harus benar-benar memastikan bahwa kedua dokumen dibuat secara identik, jadi itu sebabnya saya harus menjalankan JSON.parse(JSON.stringify(doc.toObject()) ) di kedua dokumen.

Ya dalam hal ini Anda harus melakukan JSON.parse(JSON.stringify()) , itu cara termudah untuk mengonversi semua id objek menjadi string.

JSON.parse(JSON.stringify()) terlalu intensif secara komputasi untuk saya, jadi saya harus membuat lib perf-thinking ini .

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'

Fitur Mongo ini sangat disesalkan

@ZacharyRSmith Lalu bagaimana dengan alat peraga lainnya, mis. author_id(ObjectId mengacu pada Model Pengguna)/author_ids(array ObjectIds)?

@flight9 Anda dapat memberi tahu transformProps() untuk mencari beberapa kunci. lihat tes ini di sini: https://github.com/ZacharyRSmith/transform-props/blob/master/index.test.js#L67

saya percaya Anda bisa mendapatkan apa yang Anda inginkan dengan ini:

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

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

@ZacharyRSmith Terima kasih atas solusi Anda, Luar biasa!

Saya pikir saya melewatkan satu hal penting: Saya tidak tahu bidang mana yang ObjectId sebelumnya, karena alat yang saya tulis harus diterapkan ke semua model dalam proyek kami, yang mungkin memiliki beberapa bidang ObjectId atau tidak memilikinya, dan nama bidangnya tidak tentu.
Jadi setelah beberapa jam mencoba, saya punya solusi:

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

Ya dalam hal ini Anda perlu melakukan JSON.parse(JSON.stringify()), itu cara termudah untuk mengubah semua id objek menjadi string.

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

tldr; JSON.parse(JSON.stringify()) adalah tugas pemblokiran yang sinkron, dan dapat menyebabkan kemacetan yang serius. Ini seharusnya bukan solusi yang diterima/disarankan untuk masalah ini ...

Anda juga harus dapat melakukan mongoose.Types.ObjectId.prototype.toJSON = function() { return this.toString(); . Tetapi bahkan artikel itu mengatakan, JSON.parse(JSON.stringify) adalah salah satu cara yang lebih cepat untuk melakukan kloning dalam, masalah mereka adalah kloning dalam yang tidak perlu berulang kali

Jadi, inilah 2019.
Apakah kita belum memiliki cara yang bagus dan bersih dan jelas untuk mendapatkan string hex dari setiap instance ObjectId pada objek?

@gitowiec

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

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

@vkarpov15 sepertinya ini bukan solusi saat menggunakan 'lean'.
Jadi jika hasil yang diinginkan adalah mengembalikan objek json biasa dengan string objectIds, tampaknya cara paling efisien untuk mencapai ini adalah dengan tetap menggunakan JSON.parse(JSON.stringify()) dengan opsi lean .

Atau mungkin plugin ramping: https://www.npmjs.com/package/mongoose-lean-objectid-string

@nhitchins benar, Anda harus menggunakan plugin seperti luwak-lean-getters .

@vkarpov15 apakah ini juga berfungsi dengan skema diskriminator? Saya memiliki skema dasar dari mana saya membuat varian. Saya mencoba mengatur getter pada skema dasar. Saya menggunakan lean() dan menggunakan luwak-lean-getter tetapi saya tidak bisa membuatnya berfungsi.

@pwrnrd bisakah Anda membuka edisi baru dan mengikuti template edisi? Ini harus bekerja dengan baik dengan skema diskriminator.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat