Home > Software design >  Make string operations on field in mongodb collection (Aggregation & regex)
Make string operations on field in mongodb collection (Aggregation & regex)

Time:11-03

I am using a collection in Mongo with a price field with multiple money type :

{
  price: '15 gp' // 15 gold pieces
}

or

{
  price: '4 sp' // 0.4 gold pieces
}

I'm looking for a way to modify this field before querying the collection.

For example doing string modifications to remove the gp/sp and doing math operations to have a correct price in "GP" (1 GP = 10 SP)

This would help ordering the collection since mongo can't understand that 10 sp < 2 gp.

Is there a way to use Aggregation and regex to do it ?

CodePudding user response:

first add new field as rate and check the gp or sp and put rate of each price for example sp have rate of 10 and gp have rate of 1 then add universalprice field with multiply of rate of price and value of price after that you could compare price

db.collection.aggregate([
  {
    "$addFields": {
      "newField": {
        "$split": [
          "$price",
          ","
        ]
      }
    }
  },
  {
    "$project": {
      price: {
        $reduce: {
          input: "$newField",
          initialValue: "",
          in: {
            $concat: [
              "$$value",
              "$$this"
            ]
          }
        }
      }
    }
  },
  {
    "$addFields": {
      "rate": {
        "$switch": {
          "branches": [
            {
              "case": {
                "$regexMatch": {
                  "input": "$price",
                  "regex": ".*gp*."
                }
              },
              "then": "1"
            },
            {
              "case": {
                "$regexMatch": {
                  "input": "$price",
                  "regex": ".*sp*."
                }
              },
              "then": "10"
            }
          ],
          default: 1
        }
      }
    }
  },
  {
    "$project": {
      price: 1,
      universalPrice: {
        "$multiply": [
          {
            "$toInt": "$rate"
          },
          {
            "$toInt": {
              $first: {
                "$split": [
                  "$price",
                  " "
                ]
              }
            }
          }
        ]
      }
    }
  }
])

https://mongoplayground.net/p/S5EIUdWRp5W

CodePudding user response:

You can use this aggregation stage to convert the price field value:

db.collection.aggregate([
  { 
      $addFields: { 
          price: {
              $function: {
                  body: function(inPrice) {
                               let outPrice;
                               if (/gp/.test(inPrice)) {
                                   outPrice = parseInt(inPrice.replace("gp", "").trim()) * 10;
                               }
                               else if (/sp/.test(inPrice)) {
                                   outPrice = parseInt(inPrice.replace("sp", "").trim());
                               }
                               else {
                                   outPrice = inPrice; // whatever needs here...
                               }
                               return outPrice;
                  },
                  args: [ "$price" ],
                  lang: "js"
              }
          }
      }
  }
])

For example, price: "5 gp" will convert to price: 50 and price: "12 sp" will convert to price: 12. Note the values are converted to number type fields for comparison and also calculations.

  • Related