2017-09-25 5 views
2

J'ai essayé toutes les méthodes que j'ai trouvées sur SO sans succès. Essayer pour accomplir une tâche en apparence simple (très facile avec JSON/lodash par exemple) MongoDB ..MongoDB> extraire la collection du tableau imbriqué

J'ai une collection: db.users>

[ 
    { 
     _id: 'userid', 
     profile: { 
      username: 'abc', 
      tests: [ 
       { 
        _id: 'testid', 
        meta: { 
         category: 'math', 
         date: '9/2/2017', 
         ... 
        } 
        questions: [ 
         { 
          type: 'add', 
          correct: true, 
         }, 
         { 
          type: 'subtract', 
          correct: true, 
         }, 
         { 
          type: 'add', 
          correct: false, 
         }, 
         { 
          type: 'multiply', 
          correct: false, 
         }, 

        ] 
       }, 
       ... 
      ] 
     } 
    }, 
    ... 
] 

Je veux finir avec un tableau regroupés par type de question:

[ 
    { 
     type: 'add', 
     correct: 5, 
     wrong: 3, 
    }, 
    { 
     type: 'subtract', 
     correct: 4, 
     wrong: 9 
    } 
    ... 
] 

J'ai essayé différentes variations d'agrégats, la dernière est:

db.users.aggregate([ 
    { $match: { 'profile.tests.meta.category': 'math' }}, 
    { 
     $project: { 
      tests: { 
       $filter: { 
        input: "$profile.tests", 
        as: "test", 
        cond: { $eq: ['$$test.meta.category', 'math'] } 
       } 
      } 
     } 
    }, 
    { 
     $project: { 
      question: "$tests.questions" 
     } 
    }, 
    { $unwind: "$questions"}, 

]) 

également essayé d'ajouter un groupe $ à la fin de la canalisation:

{ 
     $group: 
     { 
      _id: '$questions.type', 
      res: { 
       $addToSet: { correct: {$eq:['$questions.chosenAnswer', '$questions.answers.correct'] } 
      } 
     } 
    } 

Aucune variation m'a donné ce que je cherche, je suis sûr que je manque un concept de base, je l'ai regardé la documentation et ne pouvait pas le comprendre .. ce que je cherche essentiellement est un flatMap pour extraire toutes les questions de tous les utilisateurs et les regrouper par type.

Si quelqu'un peut me guider dans la bonne direction, j'apprécierai beaucoup :) thx. (En outre, j'utilise Meteor, donc toute requête doit fonctionner dans Meteor mongo)

+0

Désolé, seuls les champs copiés pertinents, mais il est une erreur, devrait être meta> catégorie> mathématiques au lieu de la catégorie juste .. Je vais mettre à jour le Q, thx – webkit

Répondre

2

Vous pouvez essayer d'agrégation ci-dessous en 3.4.

$filter pour filtrer math catégories avec $map à projeter ensemble questions dans chaque catégorie correspondant suivi par $reduce et $concatArrays pour obtenir tous questions dans un tableau unique pour toutes les catégories correspondant.

tableau $unwind de questions et $group par type et $sum pour calculer le nombre correct et wrong.

db.users.aggregate([ 
    { 
    "$match": { 
     "profile.tests.meta.category": "math" 
    } 
    }, 
    { 
    "$project": { 
     "questions": { 
     "$reduce": { 
      "input": { 
      "$map": { 
       "input": { 
       "$filter": { 
        "input": "$profile.tests", 
        "as": "testf", 
        "cond": { 
        "$eq": [ 
         "$$testf.meta.category", 
         "math" 
        ] 
        } 
       } 
       }, 
       "as": "testm", 
       "in": "$$testm.questions" 
      } 
      }, 
      "initialValue": [], 
      "in": { 
      "$concatArrays": [ 
       "$$value", 
       "$$this" 
      ] 
      } 
     } 
     } 
    } 
    }, 
    { 
    "$unwind": "$questions" 
    }, 
    { 
    "$group": { 
     "_id": "$questions.type", 
     "correct": { 
     "$sum": { 
      "$cond": [ 
      { 
       "$eq": [ 
       "$questions.correct", 
       true 
       ] 
      }, 
      1, 
      0 
      ] 
     } 
     }, 
     "wrong": { 
     "$sum": { 
      "$cond": [ 
      { 
       "$eq": [ 
       "$questions.correct", 
       false 
       ] 
      }, 
      1, 
      0 
      ] 
     } 
     } 
    } 
    } 
]) 
+1

vous sérieusement ma journée .. merci de prendre le temps. – webkit

+0

Je suis nouveau sur MongoDB, essayant de comprendre exactement ce que vous avez fait, je vais creuser profondément sur $ réduire, c'est sûr :), il semble que cette requête tourne vraiment vite lors des tests, avez-vous des conseils pour d'autres optimisations? Je sais que des index devraient être créés, est-ce pertinent ici? On m'a dit d'extraire toutes les questions à leur propre collection .. est-ce quelque chose que vous suggérer de faire dans ce cas .. ou ils sont bons où ils sont? Je vous remercie. – webkit

+0

Np. Vous ne pouvez utiliser que des index pour l'étape '$ match'. Donc, ajoutez l'index de 'profile.tests.meta.category'. Vous devez tester toutes les options avant d'en choisir une. J'essaierais aussi de déplacer les questions au plus haut niveau et dans leur propre tableau avec des méta-données pertinentes pour les relier au test associé (en dupliquant essentiellement certaines des données). Vous pouvez également ajouter '$ match' pour les questions dont vous avez besoin. Comparez cette option avec la structure et l'option en cours de déplacement dans sa propre collection. – Veeram