Dallas Baker
Dallas Baker

Reputation: 376

MongoDB upsert an array of objects from a list

I am working on moving my database from sqlite3 to mongo. I went through mongo university, yet I'm not sure I have found a really good example of upsertting in bulk.

Use case : user uploads a data file with a list of players and their stats. The app needs to either update a player or add a new player if they do not already exist.

Current Implementation : Function takes a list of Players and creates SQL statement.

let template = '(Player.Rank, Player.Player_ID, Player.Player, Player.Score, TTP, 1),(Player.Rank, Player_ID, ...) ... (... TTP, 1)';

const stmt = `INSERT INTO playerStats (Rank, Player_ID, Player, Score, TPP, Games_Played) 
VALUES ${template}
ON CONFLICT(Player_ID) DO UPDATE 
SET Score = Score+excluded.Score, TPP=TPP+excluded.TPP, Games_Played=Games_Played+1`;

db.run(stmt, callback);

Im hoping to have each document be a league which contains players, games, and managers. Mongo DB document template

{
    "LEAGUE_ID": "GEO_SAM",
      "Players": [
        {
          "id": "PlayerID",
          "name": "Player",
          "score": "Score",
          "rank": "Rank",
          "xPlayed": "Games_Played",
          "ttp": "TTP"
        }
      ],
      "Managers": [
        {...}
      ],
      "Games": [
        {...}
      ]
  }

I am totally lost and not sure how to get this done. Do I need to create a loop and ask mongo to upsert on each iteration? I have searched through countless examples but all of them use static hard coded values.

Here is my testing example.

const query = { League_id : "GEO_SAM", Players.$.id: $in{ $Players }};
const update = { $inc: { score: $Player.Score}};
const options = { upsert: true };
collection.updateMany(query, update, options);

I also don't understand how to pass the entire player object to push to the array if the player_id isn't found.

Upvotes: 1

Views: 126

Answers (1)

Dallas Baker
Dallas Baker

Reputation: 376

My solution was to create a metaData field containing the league ID with a single player. If anyone else has a better solution I would love to hear from you.

   {
      MetaData: { "LEAGUE_ID": "GEO_SAM"},
      Player: {
        "id": "PlayerID",
        "name": "Player",
        "score": "Score",
        "rank": "Rank",
        "xPlayed": "Games_Played",
        "ttp": "TTP"
        }
  }

Then I mapped over the values and inserted each one.

client.connect().then((client) => {
        const db = client.db(dbName);
        const results = Players.map((player) => {
          db.collection('Players').updateOne(
            { Player_Name: player.Player_ID },
            {
              $setOnInsert: {
                Player_ID: player.Player_ID,
                Player: player.Player,
                Rank: player.Rank,
              },
              $inc: { Score: player.Score, Games_Played: 1, TPP: player.TPP },
            },
            { upsert: true, multi: true },
          );
        });

Upvotes: 1

Related Questions