简体   繁体   中英

MongoDB query multiple subdocuments

My MongoDB data structure looks like this:

{
  users: [{
    userref: "User1",
    results: [{
      testref: "TEST1",
      history: [{
        score: 10
      }, {
        score: 15
      }]
    }, {
      testref: "TEST2",
      history: [{
        score: 2
      }, {
        score: 1
      }]
    }]
  }]
}

I have a collection of users, each with an array of results (one result object for each test), and within each result, an array of the history of the historical scores.

What I need to do is "return the userref for all users whose most recent score for TEST1 is X and whose most recent score for TEST2 is Y" . Users who have not completed one or other of these tests should not be returned. By "most recent", I mean the last in the array.

I'm assuming I need to use aggregation, but I'm totally new to this, so could do with some help.

This is what I have tried so far, and it works, but it only matches the condition where TEST1=15, and I would also like it to match the condition TEST2=1.

[{$unwind: {
  path: '$results’,
  preserveNullAndEmptyArrays: false
}}, {$match: {
  'results.testref': 'TEST1'
}}, {$project: {
  results: 1,
  userref: 1,
}}, {$replaceRoot: {
  newRoot: {
    $mergeObjects: [
      {
        userref: '$userref'
      },
      '$results'
    ]
  }
}}, {$project: {
  userref: 1,
  history: {
    $slice: [
      '$history',
      -1
    ]
  }
}}, {$match: {
  'history.score': 15
}}, {$project: {
  userref: 1,
}}]

Thanks

To match both the conditions,

db.getCollection('test2').aggregate([{"$unwind":"$users"}, {$unwind:"$users.results"}, 
{$project:
     {"lastScore": 
        {$slice:
            ["$users.results.history", -1]
        },
     "users.userref":1,
     "users.results.testref":1
    }
},
{
    $match:{"$or":[{
      $and:[
        {"users.results.testref":"TEST1"},
        {"lastScore.0.score":15}
      ]},
      {
      $and:[
        {"users.results.testref":"TEST2"},
        {"lastScore.0.score":1}
      ]}
      ]
    }
},
{
    $group:{
        "_id":{"_id":"$_id","userref":"$users.userref"},
        "data":{$push:{"tests":"$users.results.testref", "userref":"$users.userref"}}
    }
},
{
    $project:{
        "_id":1,
        "validUser":{
        "$filter":{
            "input":"$data",
            "as":"data",
            "cond":{$or:[{$eq:["$$data.tests","TEST1"]}, {$eq:["$$data.tests","TEST2"]}]}
        }}
    }
},
{
    $project:{
        "_id.userref":1
    }
}
])

What does the query do:

  1. Unwind users
  2. Unwind results
  3. Get last score part along with user ref, test ref
  4. Check for the necessary conditions
  5. Group back on user ref along with doc id
  6. Check whether two conditions met using $filte
  7. Project userref

Output:

/* 1 */
{
    "_id" : {
        "userref" : "User1"
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM