La requête MongoDB retourne 0 éléments à la première exécution mais réussit à la deuxième

Je constate un comportement très étrange dans un workflow n8n utilisant MongoDB.
Le workflow est :

  • Webhook reçoit LeadUserID et property_id
  • Le nœud Set formate les données
  • Le nœud MongoDB trouve le document Campaign par property_id
  • Un deuxième nœud MongoDB recherche la collection Campaign_Members en utilisant :
    • Customer_ID du webhook
    • Campaign_ID (_id) du nœud MongoDB précédent
      Le problème est que le deuxième nœud MongoDB se comporte de manière incohérente :
  • Exécution automatique du workflow → retourne 0 éléments
  • Première exécution manuelle dans l’éditeur → retourne 0 éléments
  • Deuxième exécution manuelle (sans rien modifier) → retourne avec succès le document correspondant
    La requête est :
={
  "Customer_ID": "{{ $('Edit Fields').first().json.body.args.LeadUserID }}",
  "Campaign_ID": "{{ $json._id }}"
}

Les données existent déjà dans la base de données, ce n’est donc pas une condition de concurrence avec une insertion récente.
Ce qui me confond, c’est que rien ne change entre la première et la deuxième exécution, pourtant la deuxième exécution réussit systématiquement.
Quelqu’un a-t-il rencontré ce type de comportement « première exécution échoue, deuxième exécution fonctionne » avec les nœuds MongoDB ? Pourrait-ce être lié aux types de données (comme ObjectId par rapport à une chaîne de caractères), au timing de l’évaluation des expressions, à l’état d’exécution, ou à une autre particularité spécifique à n8n ?

Informations sur votre configuration n8n

  • Version n8n : dernière version
  • Base de données (par défaut : MongoDB) :
  • Paramètre EXECUTIONS_PROCESS de n8n (par défaut : own, main) :
  • Exécution de n8n via : n8n cloud
  • Système d’exploitation :

Bonjour @alee_Ostovar

Vous devez vous assurer que Campaign_ID est transmis en tant que ObjectId.

Le moyen le plus fiable de gérer ObjectId dans n8n est de créer l’objet de requête dans un nœud Code. Cela empêche n8n de convertir accidentellement vos ID en chaînes de caractères.

  1. Ajoutez un nœud Code avant votre deuxième nœud MongoDB.
  2. Utilisez ce code :
const leadUserId = $('Edit Fields').first().json.body.args.LeadUserID;
const campaignId = $json._id;

return {
  query: {
    Customer_ID: leadUserId,
    Campaign_ID: { "$oid": campaignId } // Cela indique à MongoDB de le traiter comme un ObjectId
  }
};
  1. Dans votre nœud MongoDB, au lieu d’écrire le JSON manuellement, référencez la sortie du nœud Code : {{ $json.query }}

@alee_Ostovar
J’ai rencontré un problème très similaire avec Postgres. D’après ce que j’ai pu comprendre, c’était lié aux données épinglées au déclencheur, particulièrement si le déclencheur est un webhook ou un déclencheur « Exécuté par un autre workflow ». Bien que cela ne soit pas censé se produire, les données épinglées du déclencheur ont été transmises en aval lors des exécutions en production et parfois ces données sont incorrectes / simplement une valeur null suite à des tests manuels. Et puis quand vous ouvrez manuellement l’exécution qui a échoué - les données épinglées du déclencheur sont écrasées et cela fonctionne miraculeusement.

J’ai pu résoudre le problème en m’assurant de toujours désépingler les données du déclencheur avant que mon workflow ne soit en direct. Cela ne s’est plus produit depuis, et cela se produisait auparavant environ 50% du temps. J’espère que cela vous aidera.

Merci pour la suggestion. Dans mon cas, Campaign_ID n’est pas stocké en tant que ObjectId MongoDB. Il est stocké en tant que chaîne de caractères dans la collection Campaign_Members (c’est juste une valeur de référence, pas un véritable champ ObjectId).

Pour cette raison, l’envelopper en tant que { "$oid": campaignId } ferait que la requête cherche un ObjectId, ce qui ne correspondrait pas à la valeur de chaîne stockée.

C’est pourquoi

Cela est dû à une incompatibilité de types de données

Merci, j’ai en fait déjà essayé ça. Je me suis assuré que le déclencheur Webhook n’était pas épinglé, mais malheureusement le comportement n’a pas changé.

Une solution de contournement que j’ai trouvée est de remplacer le nœud Edit Fields (Set) par un nœud Code qui crée la même sortie. Avec le nœud Code, le workflow fonctionne correctement à chaque fois.

J’ai aussi remarqué un autre problème qui semble lié au nœud Edit Fields : lorsqu’on passe des documents MongoDB à travers celui-ci, l’_id MongoDB est parfois converti en Buffer au lieu de rester sous sa forme d’origine. Cela semble être un problème distinct avec le nœud Set/Edit Fields lui-même.

Pour le moment, utiliser un nœud Code contourne les deux problèmes, mais cela ressemble plus à éviter le bug qu’à le corriger. J’essaie de comprendre pourquoi le nœud natif Set/Edit Fields se comporte de cette façon.

Je ne pense pas que ce soit un problème d’incompatibilité de type, puisque les deux variables sont stockées sous forme de chaînes de caractères, et la requête utilise également des valeurs de chaîne. S’il s’agissait d’une incompatibilité de type, je m’attendrais à ce qu’elle échoue de manière cohérente plutôt que seulement à la première exécution.

J’ai pu résoudre le problème en remplaçant le nœud Edit Fields (Set) par un nœud Code. Cela fonctionne, mais je tente de comprendre pourquoi le nœud Set natif présente ce comportement en premier lieu.

Dans MongoDB, le champ _id n’est pas une chaîne de caractères ; c’est un type BSON spécial appelé ObjectId.

Dans votre requête :

{
  "Customer_ID": "{{ $('Edit Fields').first().json.body.args.LeadUserID }}",
  "Campaign_ID": "{{ $json._id }}"
}

En entourant {{ $json._id }} de guillemets doubles, vous dites explicitement à n8n de traiter Campaign_ID comme une chaîne de caractères. Lorsque MongoDB reçoit une chaîne pour un champ stocké sous forme d’ObjectId, il retourne zéro résultats car une chaîne n’est pas égale à un ObjectId, même si les caractères sont identiques.

Durant la première exécution manuelle, le nœud peut ne pas résoudre l’expression exactement comme prévu ou échoue la requête DB. Cependant, lors de la deuxième exécution, l’éditeur utilise souvent la sortie mise en cache de l’état d’exécution précédent du nœud.

Cela s’applique-t-il à votre cas ?

C’est exactement la partie confuse, et c’est en fait le deuxième problème auquel je suis confronté.

Le nœud Edit Fields transmet parfois _id sous la forme [object Object], donc j’ai soupçonné un problème de type de données. Pour vérifier, j’ai enregistré la valeur à l’aide d’un nœud Code immédiatement après un nœud MongoDB (avant un nœud d’édition de champs). Voici la sortie :

[
  {
    "value": "6a579e9014256aa1f68ca592",
    "typeof": "string",
    "constructor": "String",
    "isObject": false,
    "proto": "Object"
  }
]

En apparence, il s’agit d’une chaîne de caractères primitive. Cependant, compte tenu du comportement que j’observe, je soupçonne qu’il pourrait y avoir un wrapper BSON sous-jacent ou un type/proxy interne impliqué qui n’est pas reflété dans la sortie du nœud Code. Cela expliquerait pourquoi le nœud MongoDB traite ultérieurement la valeur comme un objet plutôt que comme une chaîne de caractères.

Pour forcer une chaîne primitive à chaque fois (automatique ou manuelle), vous devriez envelopper votre expression dans un constructeur de chaîne JavaScript.

Modifiez votre requête de ceci :

{
  "Customer_ID": "{{ $('Edit Fields').first().json.body.args.LeadUserID }}",
  "Campaign_ID": "{{ $json._id }}"
}

À ceci :

{
  "Customer_ID": "{{ String($('Edit Fields').first().json.body.args.LeadUserID) }}",
  "Campaign_ID": "{{ String($json._id) }}"
}

En enveloppant l’expression dans String(), vous forcez le moteur d’expression n8n à exécuter un transtypage JavaScript avant que la valeur ne soit transmise au nœud MongoDB. Cela supprime tous les wrappers BSON, proxies ou métadonnées d’objet, garantissant que MongoDB reçoit une chaîne littérale à chaque fois.