0

For example, Documents.

[
  {
    "username": "joy",
    "size_info": [
      {
        "data1": "apple bear cat",
        "data2": 100
      },
      {
        "data1": "dog eat fog good ",
        "data2": 100
      },
      {
        "data1": "hug ill jump",
        "data2": 100
      }
    ]
  }
]

I want to update the document like below.

data3 is the value split by space after getting 2 words from data1.

When I use $substr, I get an error:

can't convert from BSON type array to String

[
  {
    "username": "joy",
    "size_info": [
      {
        "data1": "apple bear cat",
        "data2": 100,
        "data3": "apple bear"
      },
      {
        "data1": "dog eat fog good ",
        "data2": 100,
        "data3": "dog eat"
      },
      {
        "data1": "hug ill jump",
        "data2": 100,
        "data3": "hug ill"
      }
    ]
  }
]

Is it possible? Thank you for helping.

Yong Shun
  • 35,286
  • 4
  • 24
  • 46
jexists
  • 171
  • 1
  • 10

1 Answers1

1

Pre-requisites: Have to update the records with the aggregation pipeline.

Solution 1: With regex

  1. $set - Set size_info array.

    1.1. $map - Iterate the element in the size_info array and return a new array.

    1.1.1. $mergeObjects - Merge the current iterated document with the result from 1.1.1.1.

    1.1.1.1. A document with data3 field. Get the first capture element from the result with the regex that captures the first two words.

db.collection.update({},
[
  {
    $set: {
      size_info: {
        $map: {
          input: "$size_info",
          in: {
            $mergeObjects: [
              "$$this",
              {
                data3: {
                  $first: {
                    $getField: {
                      field: "captures",
                      input: {
                        $regexFind: {
                          input: "$$this.data1",
                          regex: "^([^\\s]* [^\\s]*).*$"
                        }
                      }
                    }
                  }
                }
              }
            ]
          }
        }
      }
    }
  }
])

Demo Solution 1 @ Mongo Playground


Solution 2: Get the first N element with $firstN

Pre-requisites: MongoDB version 5.2

  1. $set - Set size_info array.

    1.1. $map - Iterate the element in the size_info array and return a new array.

    1.1.1. $mergeObjects - Merge the current iterated document with the result from 1.1.1.1.

    1.1.1.1. A document with data3 field. Trim the result returned from $reduce operator which will:

    a. Split the data1 by space into an array. And take the first 2 elements.

    b. Concat the value from the array (result from a) into a string with space.

db.collection.update({},
[
  {
    $set: {
      size_info: {
        $map: {
          input: "$size_info",
          in: {
            $mergeObjects: [
              "$$this",
              {
                data3: {
                  $trim: {
                    input: {
                      $reduce: {
                        input: {
                          $firstN: {
                            input: {
                              $split: [
                                "$$this.data1",
                                " "
                              ]
                            },
                            n: 2
                          }
                        },
                        initialValue: "",
                        in: {
                          $concat: [
                            "$$value",
                            " ",
                            "$$this"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            ]
          }
        }
      }
    }
  }
])

Demo Solution 2 @ Mongo Playground

Yong Shun
  • 35,286
  • 4
  • 24
  • 46