简体   繁体   中英

MongoDB Find All Matching array, return all not just unique

I have a user collection. In that collection each user when they enter a prize will have the prize id stored on their profile. Export of a typical user document below

{ 
    "_id" : ObjectId("5aacff47c67f99103bcbf693"), 
    "firstName" : "Test", 
    "lastName" : "Test", 
    "password" : "$2a$10$mJjzPFWuYPmK8A07nc284O8g9SStFpuaVzfyWOZgaCmVaomIxk5qO", 
    "email" : "test1@test.com", 
    "points" : NumberInt(6), 
    "prizes" : [
        ObjectId("5aafd1673a5b2cb294b69620"), 
        ObjectId("5aafd1673a5b2cb294b69620"), 
        ObjectId("5aafd1673a5b2cb294b69620"), 
        ObjectId("5aafd1673a5b2cb294b69620"), 
        ObjectId("5aafd1673a5b2cb294b69620"), 
        ObjectId("5ab28ca784aa6390aa5a1dba")
    ], 
    "messages" : [

    ], 
    "__v" : NumberInt(26)
}

I wrote a api call that when a user lands on their account page, it finds the user and returns their prize entires (array of prizes). I then want to use these to query the DB to find the title/content of each entry so it can be displayed on the front end.

I've done this two ways

var prizes = user.prizes

       //mongo

       ids = prizes.map(function(el) { return mongoose.Types.ObjectId(el) })

       Prize.aggregate([
        { $match: { "_id": { "$in": ids } } }

      ], function(err, ret){
        if (err) {
            return res.status(500).json({
                title: 'An error occurred',
                error: err
            });

        }
          console.log(ret)
      }
    )

or

Prize.find( { _id: prizes }, { title: 1, content: 1 }, function(err, ret){
        if (err) {
            return res.status(500).json({
                title: 'An error occurred',
                error: err
            });

        }
console.log(ret)



       })

Now the difficult part, both of these operations only return unique documents, (2) and not the 6 I wanted.

I wanted to find for every entry id then return that prize id's title and content , without caring if unique or not or have a count in response, so giving my user above it would return

{1x unique doc count 4} {1x unique doc, count 1}

or return 6 responses.

Even when I used the .count(), it only counted 2. I know I must be going about this the wrong way, as mongo is correct in that i'm asking it to find the documents matching the id's I pass it and it finds the 2 matching id's and serves them up.

Am i almost breaking it's functionality by asking it to do something different? Other options? Wrap it up in a for each in node and query each id manually and push to an array?

Get the prizes for specific user.

$unwind and $group to count no of prizes followed by $lookup to get prizes fields in 3.4.

User.aggregate([
  {"$match":{"_id":mongoose.Types.ObjectId(userid)}},
  {"$unwind":"$prizes"},
  {"$group":{"_id":"$prizes","count":{"$sum":1}}},
  {"$lookup":{
    "from":"prizes", // name of the prize collection
    "localField":"_id", 
    "foreignField":"_id",
    "as":"prizes"
  }},
  {"$addFields":{"prizes":{"$arrayElemAt":["$prizes",0]}}}
])

Get both the user and prizes.

Use $lookup followed by $map to keep the fields from lookup and use $filter with $size to count the no of prizes for each id in 3.4.

Something like

User.aggregate([
  {"$match":{"_id":mongoose.Types.ObjectId(userid)}},
  {"$lookup":{
    "from":"prizes", // name of the prize collection
    "localField":"prizes",
    "foreignField":"_id",
    "as":"prizeinfo"
  }},
  {"$addFields":{
    "prizeinfo":{
      "$map":{
        "input":"$prizeinfo",
        "as":"pi",
        "in":{
          "title":"$$pi.title",
          "content":"$$pi.content",
          "count":{
            "$size":{
              "$filter":{
                "input":"$prizes",
                "as":"p",
                "cond":{"$eq":["$$pi._id","$$p"]}
              }
            }
          }
        }
      }
    }
  }}
])

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