skip to Main Content

I have some data in a MongoDB collection that looks something like this:

db.test.insertOne(
    { "interactions": [
            {
                data: "keep",
                prompt: "prompt 1"
            },
            {
                other: "keep",
                prompt: "prompt 2"
            },
            {
                field: "no prompt"
            }
        ]}
    )

I want to iterate over all the interactions, and set prompts to an array containing the current value of prompt. Something like this:

{
  "interactions": [
    {
      "data": "keep",
      "prompt": "prompt 1",
      "prompts": [ "prompt 1" ]
    },
    {
      "other": "keep",
      "prompt": "prompt 2",
      "prompts": [ "prompt 2" ]
    },
    {
      "field": "no prompt"
    }
  ]
}

I’ve been trying to do a updateMany() with an aggregation pipeline, but am getting an error that I don’t understand. This is my update:

db.test.updateMany(
    {},
    [{
        $set: {
            interactions: {
                $map: {
                    input: "$interactions",
                    as: "interaction",
                    in: {
                        $mergeObjects: [
                            "$$interaction",
                            {
                                $cond: {
                                    if: { "$$interaction.prompt": { $exists: true } },
                                    then: {
                                        prompts: [ "$$interaction.prompt" ]
                                    },
                                    else: {}
                                }
                            }
                        ]
                    }
                }
            }
        }
    }]
    )

Running this I get an error:

Unrecognized expression ‘$$interaction.prompt’.

Running the update without the $cond works:

db.test.updateMany(
    {},
    [{
        $set: {
            interactions: {
                $map: {
                    input: "$interactions",
                    as: "interaction",
                    in: {
                        $mergeObjects: [
                            "$$interaction",
                            {
                                prompts: [ "$$interaction.prompt" ]
                            }
                        ]
                    }
                }
            }
        }
    }]
    )

but after that operation, the array element that didn’t have a prompt has an array with a null value:

{
  "interactions": [
    {
      "data": "keep",
      "prompt": "prompt 1",
      "prompts": ["prompt 1"]
    },
    {
      "other": "keep",
      "prompt": "prompt 2",
      "prompts": ["prompt 2"]
    },
    {
      "field": "no prompt",
      "prompts": [null]
    }
  ]
}

I don’t want prompts set on an element that didn’t have prompt.

So why can’t I access $$interactions.prompt within the $cond?
Alternatively, if there’s a better way to accomplish what I want to do, please let me know.

2

Answers


  1. Chosen as BEST ANSWER

    For some reason, using $not and $in didn't work in my database, although it did in the Playground. After finding an alternative here: https://stackoverflow.com/a/25515046/1303158, my final solution is:

    db.collection.update({},
    [
      {
        $set: {
          interactions: {
            $map: {
              input: "$interactions",
              as: "interaction",
              in: {
                $mergeObjects: [
                  "$$interaction",
                  {
                    $cond: {
                      if: {
                        $gt: [
                          "$$interaction.prompt",
                          null
                        ]
                      },
                      then: {
                        prompts: [
                          "$$interaction.prompt"
                        ]
                      },
                      else: {}
                    }
                  }
                ]
              }
            }
          }
        }
      }
    ],
    {
      multi: true
    })
    

    Demo @ Mongo Playground


  2. In the aggregation pipeline, you can’t use the $exists operator.

    And you must start with the $ operator but not with variable $$.

    Instead, you check whether $$interaction.prompt is neither undefined nor null.

    db.collection.updateMany({},
    [
      {
        $set: {
          interactions: {
            $map: {
              input: "$interactions",
              as: "interaction",
              in: {
                $mergeObjects: [
                  "$$interaction",
                  {
                    $cond: {
                      if: {
                        $not: {
                          $in: [
                            "$$interaction.prompt",
                            [
                              undefined,
                              null
                            ]
                          ]
                        }
                      },
                      then: {
                        prompts: [
                          "$$interaction.prompt"
                        ]
                      },
                      else: {}
                    }
                  }
                ]
              }
            }
          }
        }
      }
    ])
    

    Demo @ Mongo Playground

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search