Uploaded image for project: 'Core Server'
  1. Core Server
  2. SERVER-34973

Upsert querying an array, then pushing to this array with simple values

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major - P3
    • Resolution: Works as Designed
    • Affects Version/s: 3.6.4
    • Fix Version/s: None
    • Component/s: Write Ops
    • Labels:
      None
    • Operating System:
      ALL
    • Steps To Reproduce:
      Hide

      db.empty.update({"list": "value"}, {"$push": {list: "value", {upsert: 1});
      The field 'list' must be an array but is of type string in document {no id}

      db.empty.update({"list": {"$elemMatch": "value", {"$push": {list: "value"}}, {upsert: 1});}}
      $elemMatch needs an Object

      db.empty.update({"list": {"$in": ["value"], {"$push": {list: "value"}}, {upsert: 1});}}
      The field 'list' must be an array but is of type string in document {no id}

      db.empty.update({"list": {$in: ["value", "___wrong"], {"$push": {list: "value"}}, {upsert: 1});}}
      // success

      Show
      db.empty.update({"list": "value"}, {"$push": {list: "value", {upsert: 1}); The field 'list' must be an array but is of type string in document {no id } db.empty.update({"list": {"$elemMatch": "value" , {"$push": {list: "value"}}, {upsert: 1});}} $elemMatch needs an Object db.empty.update({"list": {"$in": ["value"] , {"$push": {list: "value"}}, {upsert: 1});}} The field 'list' must be an array but is of type string in document {no id } db.empty.update({"list": {$in: ["value", "___wrong"] , {"$push": {list: "value"}}, {upsert: 1});}} // success

      Description

      As stated in the docs:

      The update creates the new document with [...] the fields and values of both the <query> and <update> parameters if the <update> parameter contains update operator expressions. The update creates a base document from the equality clauses in the <query> parameter, and then applies the update expressions from the <update> parameter.

       

      So of course, this fails:

      db.empty.update({"list": "value"}, {"$push": {list: "value", {upsert: 1});

      with

      The field 'list' must be an array but is of type string in document {no id}

      The workaround, suggested in https://jira.mongodb.org/browse/SERVER-20203 is to add an $elemMatch to the query, so that the upserted document is not "pre-filled" with a scalar value for the list key.

      But this does not work here: $elemMatch refuses to match single values, so:

      db.empty.update({"list": {"$elemMatch": "value", {"$push": {list: "value"}}, {upsert: 1});}}

      yields

      $elemMatch needs an Object

        

      If I remember correctly, a working workaround used to be:

      db.empty.update({"list": {"$in": ["value"], {"$push": {list: "value"}}, {upsert: 1});}}

      in 3.2 or 3.4 ; but $in with single value arrays are considered equality matches in 3.6 (i'm guessing here), and this last option fails with

      The field 'list' must be an array but is of type string in document {no id}

      again.

      The only way I found to do this is

      db.empty.update({"list": {$in: ["value", "___wrong"], {"$push": {list: "value"}}, {upsert: 1});}}

      but this seems very inefficient and I would like to have a cleaner option

        Attachments

          Issue Links

            Activity

              People

              Assignee:
              asya Asya Kamsky
              Reporter:
              arthur Arthur Darcet
              Participants:
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved: