Upsert problem shaping

Hello, I am having a problem inserting into the database with an upsert push Meteor, I would like to have this form in my database

{
    "_id" : "dnP8Hu8wouBRaZ6o5",
    "userID" : "fQYGboHuxxrAu28ko",
    "2020" : {
        "Février" : [
            12,
            250,
            41
        ]
    }
}

I did this, but it registers me like this, which doesn’t suit me.

Balances.upsert(
    { userID: "fQYGboHuxxrAu28ko" },
    {
      $push: {
        [moment().format("YYYY")]: {
          [moment().format("MMMM")]: [_.sum(sommes)]
        }
      }
    }
  );
 {
    "_id" : "dnP8Hu8wouBRaZ6o5",
    "userID" : "fQYGboHuxxrAu28ko",
    "2020" : [
        {
            "March" : [
                662.619717641257
            ]
        },
        {
            "March" : [
                662.65052401921
            ]
        },
        {
            "March" : [
                660.586191114713
            ]
        }
    ]
}

Thank you for your help, I don’t know MongoDB too much

at a guess, you probably don’t want $push, but perhaps $addToSet - even that probably won’t work because a set is unique across the entire value, not just some key.

May I ask why you are not using an object?

"2020": {
March: [ 662 ]
}

then your upsert would simply be a $set

I want for example in “March” there is a table of values ​​representing the value of the balance of the day, in this example, I should have for the month of March 31 values

ahh, I see, yes - your $push isn’t correctly formed, you want something like this:

Balances.upsert(
    { userID: "fQYGboHuxxrAu28ko" },
    {
      $push: {
        [`${moment().format("YYYY")}.${moment().format("MMMM")}`]: _.sum(sommes)
      }
    }
  );
2 Likes

As a follow up, I’d recommend against an array of pure values - what happens if a sync runs twice, or a sync fails for any reason and you end up with a missing value, all subsequent values would be in the wrong “slot” better would be to $push an object { day: 1, 2, 3, ..., value: 660.00 }

thanks to you it works, I have the shape I want

yes exactly, must refacto all its

Hello, I reopen the post, because I have a little problem, I would like to have this structure, but each time he runs the upsert I only have the last value to add, but I absolutely want this structure, because it is simpler front side for graphics.

  Balances.upsert(
          { user_id: userId },
          {
            $set: {
              [moment().year()]: {
                [moment().format('M')]: {
                  [moment().format('D')]: {
                    amount: sum(balance) || 0,
                    date: new Date(),
                  },
                },
              },
            },
          }
        );
{
    "_id" : "ELw6zcznDZNLf4aHj",
    "user_id" : "Ce8CAAyCxBePee2vv",
    "balances" : {
        "2020" : {
            "8" : {
                "1" : {
                    "amount" : 1697.0785612293,
                    "date" : ISODate("2020-08-01T20:00:00.027Z")
                },
                "2" : {
                    "amount" : 1718.69859282765,
                    "date" : ISODate("2020-08-02T20:00:00.027Z")
                },
                "3" : {
                    "amount" : 1897.44350676055,
                    "date" : ISODate("2020-08-03T20:00:00.027Z")
                },
                "4" : {
                    "amount" : 1981.33613346673,
                    "date" : ISODate("2020-08-04T20:00:00.027Z")
                },
                "5" : {
                    "amount" : 1981.33613346673,
                    "date" : ISODate("2020-08-05T20:00:00.027Z")
                },
                "6" : {
                    "amount" : 1986.04695477116,
                    "date" : ISODate("2020-08-06T20:00:04.206Z")
                },
                "7" : {
                    "amount" : 1934.84381041097,
                    "date" : ISODate("2020-08-07T20:00:03.044Z")
                },
            }
        }
    }
}

When the cron runs the next day it removes everything from the previous days

{
    "_id" : "ELw6zcznDZNLf4aHj",
    "user_id" : "Ce8CAAyCxBePee2vv",
    "balances" : {
        "2020" : {
            "8" : {
                 "8" : {
                    "amount" : 1935.13192202069,
                    "date" : ISODate("2020-08-08T20:00:04.237Z")
                }
            }
        }
    }
}


Please refer to existing accepted solution:

Use a string instead of nested objects, as Mongo will take the whole object and replace the existing value matching the first key ( in your case, that’s [moment().year()] )

1 Like

Thanks it works like this,

 Balances.upsert(
          { user_id: userId },
          {
            $push: {
              [`${moment().format('YYYY')}.${moment().format(
                'M'
              )}.${moment().format('D')}`]: {
                amount: sum(balance) || 0,
                date: new Date(),
              },
            },
          }
        );

my last question is i would like to encompass everything in scales like this, how can this be done in my upsert? To make it more convenient for me to loop over each year

`{
    "_id" : "2jnNX2tpzBGwM97TZ",
    "user_id" : "Mwid5hkaBhPTpn2AB",
    "balances" : {
        "2020" : {
            "8" : {
                "1" : [ 
                    {
                        "amount" : 500,
                        "date" : ISODate("2020-08-1T18:59:00.026Z")
                    }
                ],
                "2" : [ 
                    {
                        "amount" : 800,
                        "date" : ISODate("2020-08-2T18:59:00.026Z")
                    }
                ]
}
}

I solved my problem here is the solution, thank you all for your help

 Balances.upsert(
          { user_id: userId },
          {
            $push: {
              [`${'balances'}.${moment().format('YYYY')}.${moment().format(
                'M'
              )}.${moment().format('D')}`]: {
                amount: sum(balance) || 0,
                date: new Date(),
              },
            },
          }
        );
1 Like