web-dev-qa-db-fra.com

MongoDB: associe une doc non vide dans un tableau

J'ai une collection structurée ainsi:

{
  _id: 1,
  score: [
    {
      foo: 'a',
      bar: 0,
      user: {user1: 0, user2: 7}
    }
  ]
}

Je dois trouver tous les documents comportant au moins un "score" (élément dans le tableau de scores) ayant une certaine valeur de "barre" et un sous-document "utilisateur" non vide.

Voici ce que je suis venu avec (et il semblait que cela devrait fonctionner):

db.col.find({score: {"$elemMatch": {bar:0, user: {"$not":{}} }}})

Mais je reçois cette erreur:

error: { "$err" : "$not cannot be empty", "code" : 13030 }

Une autre façon de faire ça?

31
Dmitri

Je l'ai compris: { 'score.user': { "$gt": {} } } correspondra aux documents non vides.

61
Dmitri

Je ne suis pas sûr de bien comprendre votre schéma, mais peut-être que la solution la plus simple serait de ne pas avoir une valeur "vide" pour score.user ?

À la place, volontairement not , avez-vous ce champ dans votre document s’il n’a pas de contenu?

Ensuite, votre requête pourrait être quelque chose comme ...

> db.test.find({ "score" : { "$elemMatch" : { bar : 0, "user" : {"$exists": true }}}})

c'est-à-dire que vous recherchez une valeur dansscore.barque vous souhaitez (0 dans ce cas) en recherchant l'existence de mear ($ existe, voir docs ) descore.user _ (et s'il a une valeur, alors ça existera?)

editied : oops j'ai raté le $ elemMatch que vous aviez ...

3
Justin Jenkins

Vous voudrez probablement ajouter un tableau auxiliaire qui garde la trace des utilisateurs dans le document user:

{
  _id: 1,
  score: [
    {
      foo: 'a',
      bar: 0,
      users: ["user1", "user2"],
      user: {user1: 0, user2: 7}
    }
  ]
}

Ensuite, vous pouvez ajouter de nouveaux utilisateurs de manière atomique:

> db.test.update({_id: 1, score: { $elemMatch: {bar: 0}}},                       
... {$set: {'score.$.user.user3': 10}, $addToSet: {'score.$.users': "user3"}})

Supprimer des utilisateurs:

> db.test.update({_id: 1, score: { $elemMatch: {bar: 0}}},
... {$unset: {'score.$.user.user3': 1}, $pop: {'score.$.users': "user3"}})      

Résultats de la requête:

> db.test.find({_id: 1, score: {$elemMatch: {bar: 0, users: {$not: {$size: 0}}}}})

Si vous savez que vous allez uniquement ajouter des utilisateurs non existants et supprimer des utilisateurs existants du document user, vous pouvez simplifier users en un compteur au lieu d'un tableau, mais la procédure ci-dessus est plus résiliente.

1
cwb

Regardez l'opérateur $ size pour vérifier les tailles de tableau.

0
Andreas Jung