Mongoose: Conversion de tous les ObjectIds en chaîne à l'aide de la méthode Document.toObject() ?

Créé le 25 mars 2015  ·  24Commentaires  ·  Source: Automattic/mongoose

Comme j'ai trouvé que le _id dans le document est toujours un ObjectId après toObject()

Existe-t-il un moyen d'y parvenir?

help

Commentaire le plus utile

Cette fonctionnalité de Mongo est vraiment regrettable

Tous les 24 commentaires

J'ai le même bug. toJSON() et toObject() ne chaînent pas les instances ObjectId .

C'est par conception pour le moment, car les ObjectIds ne sont techniquement pas des chaînes. Du haut de ma tête, la seule façon à laquelle je peux penser serait de JSON.parse(JSON.stringify(doc)); Quel est votre cas d'utilisation pour chaîner tous les identifiants d'objets ?

donc, la fonction toJSON() ne convertit pas l'objet en chaîne JSON ? Le _id et la date ne sont pas une chaîne mais un objet ?

au fait, quelle est la différence entre toObject() et toJSON() ?
THX!

Ouais, la date devrait toujours être une date, pas une chaîne, après toJSON() + toObject() .

toJSON() et toObject() sont essentiellement identiques, la seule différence est que lorsque vous faites JSON.stringify(doc) JavaScript recherche une fonction toJSON() sur doc et l'utilise pour convertir le objet. Donc, la raison de toJSON() est le sucre syntaxique pour JSON.stringify() .

@ vkarpov15 Désolé de commenter un problème fermé, mais cela semblait l'endroit le plus pertinent pour publier, car il est directement lié à ce problème.

J'essaie de comparer en profondeur deux documents de mangouste pour obtenir un objet diff des changements entre eux.
Cependant, les ObjectID ne peuvent pas être comparés directement, car ils se retrouveront toujours avec un diff, même s'ils contiennent exactement les mêmes identifiants.

La seule façon dont j'ai pu le faire jusqu'à présent, c'est de faire ceci:

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

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

Cela semble être un moyen coûteux d'obtenir un diff entre les objets.
Connaissez-vous un meilleur moyen de comparer de manière fiable les documents de mangouste ?

Vous ne savez pas à quel point la différence de profondeur fonctionne, mais il se peut que vous rencontriez des problèmes avec mongodb ObjectIds. Essayez de convertir _id et d'autres champs objectid en chaînes. Ou utilisez simplement la vérification d'égalité profonde de lodash, je pense que l'on fonctionne avec ObjectIds

@ vkarpov15 deep diff utilise lodash pour le contrôle d'égalité, donc malheureusement cela ne fonctionnera pas:
https://github.com/rbs392/object-deep-diff/blob/master/index.js

La conversion de tous les ObjectId en chaînes fonctionnerait, mais comme les objets peuvent contenir des tableaux et/ou d'autres objets imbriqués, cela devient également une tâche assez coûteuse. :/

Voici donc une autre question, utilisez-vous deep-diff sur 2 documents mangouste ou 2 documents qui sont le résultat de toObject() ? Ce dernier devrait fonctionner, le premier pas tellement.

@ vkarpov15 c'est généralement 1 doc mangouste (converti en objet javscript avec .toObject) et un objet javascript normal.
La raison en est que j'ai besoin de comparer les données provenant du client avec les données déjà présentes dans la base de données.
Ainsi, les données provenant du client ont déjà converti les ObjectID, mais pas les données provenant de la base de données.
Mais comme je fais cette vérification en profondeur dans un plugin mangouste, je dois m'assurer que les deux documents sont construits de manière identique, c'est pourquoi je dois exécuter JSON.parse(JSON.stringify(doc.toObject()) ) sur les deux docs.

Ouais, dans ce cas, vous devrez faire JSON.parse(JSON.stringify()) , c'est le moyen le plus simple de convertir tous les identifiants d'objets en chaînes.

JSON.parse(JSON.stringify()) était trop gourmand en calculs pour moi, j'ai donc dû créer cette lib perf-pensée .

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'

Cette fonctionnalité de Mongo est vraiment regrettable

@ZacharyRSmith Alors qu'en est-il des autres accessoires, par exemple. author_id (ObjectId fait référence au modèle utilisateur)/author_ids (tableau d'ObjectIds) ?

@ flight9 , vous pouvez dire à transformProps() de rechercher plusieurs clés. voir ce test ici : https://github.com/ZacharyRSmith/transform-props/blob/master/index.test.js#L67

je crois que tu peux obtenir ce que tu veux avec ceci:

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

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

@ZacharyRSmith Merci pour votre solution, c'est génial !

Je pense que j'ai raté une chose importante: je ne sais pas quels champs sont ObjectId à l'avance, car l'outil que j'écris doit être appliqué à tous les modèles de notre projet, qui peuvent avoir plusieurs champs ObjectId ou n'en avoir aucun, et ses noms de champs sont indéterminés.
Donc après plusieurs heures d'essais, j'ai ma solution :

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

Ouais, dans ce cas, vous devrez faire JSON.parse(JSON.stringify()), c'est le moyen le plus simple de convertir tous les identifiants d'objets en chaînes.

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

tldr ; JSON.parse(JSON.stringify()) est une tâche bloquante synchrone et peut provoquer de sérieux goulots d'étranglement. Cela ne devrait pas être la solution acceptée/suggérée pour ce problème...

Vous devriez également être capable de faire mongoose.Types.ObjectId.prototype.toJSON = function() { return this.toString(); . Mais même cet article dit, JSON.parse(JSON.stringify) est l'un des moyens les plus rapides de faire un clonage en profondeur, leur problème était qu'ils clonaient inutilement en profondeur à plusieurs reprises

Alors, voici 2019.
Avons-nous encore un moyen agréable, propre et évident d'obtenir une chaîne hexadécimale à partir de chaque instance d'ObjectId sur un objet ?

@ vkarpov15 semble que ce n'est pas une solution lors de l'utilisation de 'lean'.
Donc, si le résultat souhaité est de renvoyer un objet json simple avec une chaîne objectIds, il semble que le moyen le plus efficace d'y parvenir consiste à toujours utiliser JSON.parse(JSON.stringify()) avec l'option lean .

Ou éventuellement un plugin allégé : https://www.npmjs.com/package/mongoose-lean-objectid-string

@nhitchins correct, vous devrez utiliser un plugin comme mongoose-lean-getters .

@ vkarpov15 est-ce également censé fonctionner avec un schéma discriminateur ? J'ai un schéma de base à partir duquel je crée des variantes. J'ai essayé de définir des getters sur le schéma de base. J'utilise lean() et j'ai utilisé des mongoose-lean-getters mais je n'ai pas réussi à le faire fonctionner.

@pwrnrd pouvez-vous s'il vous plaît ouvrir un nouveau problème et suivre le modèle de problème ? Cela devrait fonctionner correctement avec un schéma de discriminateur.

Cette page vous a été utile?
0 / 5 - 0 notes