108 votes

Dans mongoDb, comment supprimer un élément de tableau par son index ?

Dans l'exemple suivant, supposons que le document se trouve dans le répertoire db.people collection.

Comment supprimer le 3ème élément du intérêts par son indice ?

{
  "_id" : ObjectId("4d1cb5de451600000000497a"),           
  "name" : "dannie",  
  "interests" : [  
    "guitar",  
    "programming",           
    "gadgets",  
    "reading"  
  ]   
}

C'est ma solution actuelle :

var interests = db.people.findOne({"name":"dannie"}).interests;  
interests.splice(2,1)  
db.people.update({"name":"dannie"}, {"$set" : {"interests" : interests}});

Y a-t-il un moyen plus direct ?

0 votes

151voto

Javier Ferrero Points 3582

Il n'existe pas de moyen direct de tirer/supprimer par indice de tableau. En fait, c'est un problème ouvert http://jira.mongodb.org/browse/SERVER-1014 vous pouvez voter pour.

La solution de rechange consiste à utiliser $unset puis $pull :

db.lists.update({}, {$unset : {"interests.3" : 1 }}) 
db.lists.update({}, {$pull : {"interests" : null}})

Mise à jour : comme mentionné dans certains commentaires, cette approche n'est pas atomique et peut causer des conditions de course si d'autres clients lisent et/ou écrivent entre les deux opérations. Si nous avons besoin que l'opération soit atomique, nous pouvons le faire :

  • Lire le document à partir de la base de données
  • Mettre à jour le document et supprimer l'élément dans le tableau
  • Remplace le document dans la base de données. Pour s'assurer que le document n'a pas été modifié depuis que nous l'avons lu, nous pouvons utiliser le modèle update if current décrit ci-dessous dans la documentation de mongo

38 votes

Cela fait un an et demi ? Est-ce toujours l'état des choses avec mongodb ?

0 votes

La réponse suivante est plus directe et a fonctionné pour moi. Bien qu'il ne s'agisse pas d'une suppression par index, mais plutôt d'une suppression par valeur.

2 votes

@Javier - Cette solution ne vous exposerait-elle pas à des problèmes si la base de données changeait entre le moment où vous avez compté la position dans l'index et le moment où vous avez effectué la réinitialisation ?

20voto

Sunseeker Points 1028

Vous pouvez utiliser $pull modificateur de update pour supprimer un élément particulier d'un tableau. Dans le cas où vous avez fourni une requête, celle-ci ressemblera à ceci :

db.people.update({"name":"dannie"}, {'$pull': {"interests": "guitar"}})

Vous pouvez également envisager d'utiliser $pullAll pour supprimer toutes les occurrences. Plus d'informations à ce sujet sur la page de documentation officielle - http://www.mongodb.org/display/DOCS/Updating#Updating-%24pull

Cette méthode n'utilise pas l'indice comme critère de suppression d'un élément, mais elle peut néanmoins être utile dans des cas similaires au vôtre. IMO, l'utilisation des index pour adresser les éléments dans un tableau n'est pas très fiable puisque mongodb n'est pas cohérent sur l'ordre des éléments pour autant que je sache.

6 votes

Son élément est un tableau dans la question. Mongo est cohérent sur l'ordre dans ce cas. En fait, tous les documents sont en réalité des collections ordonnées, mais de nombreux pilotes ne les gèrent pas de cette manière. Pour compliquer encore l'affaire, si un document doit être déplacé après une opération de mise à jour (en raison d'une croissance supérieure au facteur de remplissage), l'ordre des clés devient soudainement alphabétique (sous les couvertures, je pense qu'elles sont triées par leur valeur binaire, cette suspicion est basée sur ma connaissance que les tableaux sont à peu près des documents standard avec des clés qui sont des entiers consécutifs au lieu de chaînes de caractères).

0 votes

Cela évite les problèmes de unset+pull, mais exige que votre dictionnaire soit strictement ordonné. Dans la plupart des langues, les dictionnaires ne sont pas ordonnés, ce qui peut s'avérer difficile à réaliser.

0 votes

@marr75 : Avez-vous une référence ? Les documents Mongo sont toujours censés conserver l'ordre, et si jamais il réordonnait les sous-documents, beaucoup de choses se casseraient.

9voto

Ali Points 1597

Dans Mongodb 4.2 vous pouvez le faire :

db.example.update({}, [
     {$set: {field: {
           $concatArrays: [ 
                  {$slice: ["$field", P]}, 
                  {$slice: ["$field", {$add: [1, P]}, {$size: "$field"}]}
           ]
     }}}
]);

P est l'index de l'élément que vous voulez enlever du tableau.

Si vous voulez enlever de P jusqu'à la fin :

db.example.update({}, [
     {$set: {field: {$slice: ["$field", P]}}
]);

6voto

Xavier Guihot Points 6414

À partir de Mongo 4.4 le $function L'opérateur d'agrégation permet d'appliquer une fonction javascript personnalisée pour mettre en œuvre un comportement non pris en charge par le langage de requête MongoDB.

Par exemple, pour mettre à jour un tableau en supprimant un élément à un indice donné :

// { "name": "dannie", "interests": ["guitar", "programming", "gadgets", "reading"] }
db.collection.update(
  { "name": "dannie" },
  [{ $set:
    { "interests":
      { $function: {
          body: function(interests) { interests.splice(2, 1); return interests; },
          args: ["$interests"],
          lang: "js"
      }}
    }
  }]
)
// { "name": "dannie", "interests": ["guitar", "programming", "reading"] }

$function prend 3 paramètres :

  • body qui est la fonction à appliquer, dont le paramètre est le tableau à modifier. La fonction ici consiste simplement à utiliser splice pour enlever 1 élément à l'indice 2.
  • args qui contient les champs de l'enregistrement que l'utilisateur a choisi. body prend comme paramètre. Dans notre cas "$interests" .
  • lang qui est la langue dans laquelle l body est écrite. Seulement js est actuellement disponible.

4voto

Stephen Orr Points 151

Plutôt que d'utiliser la fonction unset (comme dans la réponse acceptée), je résous le problème en donnant au champ une valeur unique (c'est-à-dire non NULL), puis en retirant immédiatement cette valeur. C'est un peu plus sûr d'un point de vue asynchrone. Voici le code :

    var update = {};
    var key = "ToBePulled_"+ new Date().toString();
    update['feedback.'+index] = key;
    Venues.update(venueId, {$set: update});
    return Venues.update(venueId, {$pull: {feedback: key}});

Espérons que Mongo s'occupera de ce problème, peut-être en étendant le modificateur $position pour supporter $pull ainsi que $push.

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