Home > Software engineering >  How to insert in the smallest sub-array with mongobd?
How to insert in the smallest sub-array with mongobd?

Time:09-07

I have a game collection that looks like this:

[
  {
    _id: ObjectId("6314dc4de4ad4c8141ce0b08"),
    status: "started",
    channel: "myChannel",
    teams: [
      {
        name: "myFirstTeam",
        score: 0,
        users: [
          {
            id: 9082376,
            name: "myFirstUser"
          },
          {
            id: 289168,
            name: "mySecondUser"
          },
          
        ]
      },
      {
        name: "mySecondTeam",
        score: 0,
        users: [
          {
            id: 898323,
            name: "myThirdUser"
          }
        ]
      }
    ]
  }
]

I managed to add a user to a team of a specific size:

db.collection.update({
  "channel": "myChannel",
  "teams.users": {
    $size: 1
  }
},
{
  $push: {
    "teams.$.users": {
      id: 23424234,
      name: "myUserName"
    }
  }
})

My goal is to add a user to a specific game on the smallest team. I'm new with mongodb, I don't even know if that's possible with a request only. I see the $min and $count but I can't find how to use it.

You can try on this playground

BONUS: Check to make sure the userId added is not already on any team of this game, inside the query (but I can check that before or/and after)

CodePudding user response:

Query

  • update pipeline, because you need more complicated update
  • it could be smaller with more queries but this does all with 1 query
  • find the number of members of the smallest team for example size=1
  • reduce the teams, with initial value {found false new-teams []} if we are in the team with the smallest size, we add the new member, and turn found to true, else we just add the team as it is

*i didn't added way to check if user exists, its not hard to add it, but i didnt know what to do if it existed and what to do if didnt exist, query is big and you are new, dont know if it will help you, i cant think now of smaller way to do it with 1 query

Playmongo

updateOne(
{"channel": {"$eq": "myChannel"}},
[{"$set": {"new-member": {"id": 23424234, "name": "myUserName"}}},
 {"$set": 
   {"min-size": 
     {"$min": 
       {"$map": 
         {"input": "$teams", "as": "t", "in": {"$size": "$$t.users"}}}}}},
 {"$set": 
   {"teams": 
     {"$reduce": 
       {"input": "$teams",
        "initialValue": {"added": false, "new-teams": []},
        "in": 
         {"$let": 
           {"vars": {"v": "$$value", "t": "$$this"},
            "in": 
             {"$cond": 
               [{"$or": 
                   ["$$v.added", {"$gt": 
                                  [{"$size": "$$t.users"}, "$min-size"]}]},
                 {"added": "$$v.added",
                  "new-teams": {"$concatArrays": ["$$v.new-teams", ["$$t"]]}},
                 {"added": true,
                  "new-teams": 
                   {"$concatArrays": 
                     ["$$v.new-teams",
                       [{"$mergeObjects": 
                           ["$$t",
                             {"users": 
                               {"$concatArrays": 
                                 ["$$t.users", ["$new-member"]]}}]}]]}}]}}}}}}},
 {"$set": 
   {"teams": {"$getField": {"field": "new-teams", "input": "$teams"}}}},
 {"$unset": ["new-member", "min-size"]}])
  • Related