101 votes

Mongoose : CastError : Le transfert vers ObjectId a échoué pour la valeur "[objet Object]" au niveau du chemin "_id".

Je suis nouveau dans le monde de node.js, donc j'ai le sentiment que c'est quelque chose de stupide que j'ai négligé, mais je n'ai pas été capable de trouver une réponse qui résout mon problème. Ce que j'essaie de faire est de créer un chemin qui va créer un nouvel objet enfant, l'ajouter au tableau des enfants du parent, puis retourner l'objet enfant au demandeur. Le problème que je rencontre est que si je passe la chaîne id dans findById, le nœud se plante avec

Erreur de type : Object {} ne possède pas de méthode 'cast'.

Si j'essaie de passer un ObjectId à la place, j'obtiens

CastError : Le transfert vers ObjectId a échoué pour la valeur "[objet Object]" au niveau du chemin "_id".

Voici un aperçu de mon code :

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId; //Have also tried Schema.Types.ObjectId, mongoose.ObjectId

mongoose.connect('mongodb://user:password@server:port/database');

app.get('/myClass/:Id/childClass/create', function(request, result) {
  var id = new ObjectId(request.params.Id);
  MyClass.findById(id).exec( function(err, myClass) {
    if (err || !myClass) { result.send("error: " + err + "<br>" + JSON.stringify(id) || ("object '" + request.params.Id + "' not found: " + id)); return; }
    var child = ChildClass();
    myClass.Children.addToSet(child);
    myClass.save();
    result.send(child);
  });
});

Si j'exécute ce code avec le chemin "/myClass/51c35e5ced18cb901d000001/childClass/create", voici le résultat du code :

erreur : CastError : Le transfert vers ObjectId a échoué pour la valeur "[objet Object]" au chemin "_id". {"path":"51c35e5ced18cb901d000001","instance":"ObjectID","validators":[],"setters":[],"getters":[],"_index":null}

J'ai essayé d'utiliser findOne et de passer {_id:id} à la place, mais il semble que ce soit exactement ce que fait findById. J'ai essayé les différentes classes pour ObjectId que j'ai vues sur d'autres sites. J'ai essayé d'appeler ObjectId() comme une fonction au lieu d'un constructeur et cela renvoie undefined. À ce stade, je suis à court d'idées et il ne semble pas que la recherche d'une réponse sur Google m'aide. Avez-vous une idée de ce que je fais de mal ?

De plus, comme je l'ai dit, je suis novice en matière de node/Mongo/Mongoose/Express, donc s'il existe une meilleure façon d'atteindre mon objectif, faites-le moi savoir. J'apprécie tous les commentaires.

EDIT :

Après la solution de Peter Lyons, j'ai cherché sur Google une autre erreur que je rencontrais et j'ai trouvé findByIdAndUpdate, qui fonctionne comme prévu et fait exactement ce que j'espérais faire. Je ne suis toujours pas sûr de la raison pour laquelle findById et findOne me posaient de tels problèmes et je suis curieux de le savoir (peut-être qu'un rapport de bogue doit être rempli), donc je laisse cette question ouverte au cas où quelqu'un d'autre aurait une réponse.

93voto

Peter Lyons Points 47794

Réponse courte : utiliser mongoose.Types.ObjectId .

Mongoose (mais pas mongo) peut accepter les identifiants d'objets sous forme de chaînes et les "couler" correctement pour vous, donc utilisez simplement :

MyClass.findById(req.params.id)

Cependant, la mise en garde est que si req.params.id n'est pas un format valide pour une chaîne d'identifiant mongo, cela déclenchera une exception que vous devrez attraper.

Donc la principale chose déroutante à comprendre est que mongoose.SchemaTypes contient des éléments que vous n'utilisez que pour définir des schémas mongoose, et mongoose.Types contient les éléments que vous utilisez lorsque vous créez des objets de données que vous souhaitez stocker dans la base de données ou des objets de requête. Ainsi, mongoose.Types.ObjectId("51bb793aca2ab77a3200000d") fonctionne, vous donnera un objet que vous pouvez stocker dans la base de données ou utiliser dans des requêtes, et lancera une exception si on lui donne une chaîne d'identification invalide.

findOne prend un objet de requête et transmet une seule instance de modèle à la fonction de rappel. Et findById est littéralement une enveloppe de findOne({_id: id}) ( voir le code source ici ). Juste find prend un objet de requête et passe un tableau d'instances de modèles correspondants à la fonction de rappel.

Allez-y doucement. C'est déroutant, mais je peux vous garantir que vous êtes dérouté et que vous ne rencontrez pas de bugs dans Mongoose à ce stade. C'est une bibliothèque assez mature, mais il faut du temps pour s'y habituer.

L'autre chose suspecte que je vois dans votre extrait est de ne pas utiliser new lors de l'instanciation de ChildClass . Au-delà de cela, vous devrez poster votre code de schéma afin que nous puissions vous aider à dépister les CastErrors qui subsistent.

60voto

gsalgadotoledo Points 1165

J'ai rencontré cette erreur, c'est parce que la valeur que vous voulez filtrer dans le champ _id n'est pas dans un format ID, un "si" devrait résoudre votre erreur.

const mongoose = require('mongoose');

console.log(mongoose.Types.ObjectId.isValid('53cb6b9b4f4ddef1ad47f943'));
// true
console.log(mongoose.Types.ObjectId.isValid('whatever'));
// false

Pour résoudre ce problème, vérifiez toujours si la valeur du critère de recherche est un ObjectId valide.

const criteria = {};
criteria.$or = [];

if(params.q) {
  if(mongoose.Types.ObjectId.isValid(params.id)) {
    criteria.$or.push({ _id: params.q })
  }
  criteria.$or.push({ name: { $regex: params.q, $options: 'i' }})
  criteria.$or.push({ email: { $regex: params.q, $options: 'i' }})
  criteria.$or.push({ password: { $regex: params.q, $options: 'i' }})
}

return UserModule.find(criteria).exec(() => {
  // do stuff
})

5voto

Zonic Points 135

Pour toutes les personnes qui ont été confrontées à ce problème, mais qui n'ont toujours pas réussi à le résoudre : Je suis tombé sur la même erreur et j'ai trouvé la _id étant vide.

Je l'ai décrit ici de manière plus détaillée. Je n'ai toujours pas trouvé de solution, si ce n'est de modifier les champs dans le fichier _id à des champs non-ID, ce qui me semble être un sale coup. Je vais probablement déposer un rapport de bogue pour la mangouste. Toute aide serait appréciée !

Edit : J'ai mis à jour mon fil de discussion. J'ai rempli un ticket et ils ont confirmé la disparition _id problème. Il sera corrigé dans la version 4.x.x qui a une release candidate disponible dès maintenant. La rc n'est pas recommandée pour une utilisation productive !

4voto

ac360 Points 911

Si vous rencontrez ce problème et que vous effectuez un populage quelque part dans la ligne, voir ce numéro de Mongoose .

Mise à jour vers Mongoose 4.0 et le problème a été corrigé.

2voto

camstuart Points 59

J'ai eu le même problème, j'ai juste transformé l'identifiant en chaîne.

Mon schéma :

const product = new mongooseClient.Schema({
    retailerID: { type: mongoose.SchemaTypes.ObjectId, required: true, index: true }
});

Et ensuite, lors de l'insertion :

retailerID: `${retailer._id}`

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X