mongodbstudio3t

Use toString() in Mongodb projection


I am not sure if this is a MongoDB issue I am facing or one of the tools ( NoSQLBooster , Studio 3T ) . I can use the following code in NoSQLBooster and it works. But Studio 3T complains about invalid JSON. I think I prefer studio 3T as it seems to have a lot more features , is there a workaround to make this valid JSON? It has a problem with the .toString() parts of the projection saying "invalid JSON" ( although this will work in NoSQLBooster ) .

$project:
    {
        _id: 0,
        "Country": "$country",
        "Zip From": {
            $cond: {
                if: { "$lt": [{ "$strLenCP": "$postcodeFrom" }, 4] },
                then: { $concat: ["0", "$postcodeFrom".toString()] },
                else: "$postcodeFrom".toString()
            }
        },
        "FRPUW": "0",
        "Estimated Delivery (days)": "$rate.serviceDeliveryDays"
    }

Solution

  • What you can use here is $substr or $substrBytes or $substrCP in modern versions. The first is considered deprecated in new releases and is "aliased" to $substrBytes. It has long had the effect of turning an "integer/double" into a string:

     { "$project": {
       "_id": 0,
       "Country": "$country",
       "Zip From": {
          "$cond": {
            "if": { "$lt": [{ "$strLenCP": { "$substr": ["$postcodeFrom",0,10] } }, 4] },
            "then": { "$concat": ["0", { "$substr": ["$postcodeFrom",0,10] }] },
            "else": { "$substr": ["$postcodeFrom", 0, 10 ] }
          }
       },
       "FRPUW": "0",
       "Estimated Delivery (days)": "$rate.serviceDeliveryDays"
     }}
    

    From MongoDB 4.0 you can use the $toString alias to $convert instead:

     { "$project": {
       "_id": 0,
       "Country": "$country",
       "Zip From": {
          "$cond": {
            "if": { "$lt": [{ "$strLenCP": { "$toString": "$postcodeFrom" } }, 4] },
            "then": { "$concat": ["0", { "$toString": "$postcodeFrom",0,10] }] },
            "else": { "$toString": "$postcodeFrom" }
          }
       },
       "FRPUW": "0",
       "Estimated Delivery (days)": "$rate.serviceDeliveryDays"
     }}
    

    The only "catch" with $substr and it's variants is that you need to include a maximum string length as the third argument. This can simply be any number larger than the expected length of the resulting string. Here I use 10 as a reasonable length, but if you expect a larger result then increase the number.

    The only real thing to be aware of is that using $substr will not work for other types. The more "formalized" method is the $toString which covers most cases for all "types". The actual formal $convert is really for cases where the expected "type casting" would possibly fail, and then allows an "error handler" to fall back to returning a default value or other "valid" expression.

    Moreover, as "aggregation expressions" the statements are therefor "valid" for any implementation language and not just JavaScipt, which contrary to major misconceptions is not actually a formal language of MongoDB at all, except within specialized tasks of server evaluation, which are being gradually deprecated and removed anyway.

    NOTE - There is a little "misnomer" in the question where you quote "valid JSON". This is not actually about JSON but rather the fact that the aggregation framework only understands "valid expressions" and not "JavaScript Expressions" which you are attempting to use.

    Contrary to a common misconception, when you see other code which includes a "JavaScript expression" within the content of an aggregation pipeline this code does not actually "execute on the server". What actually happens is the expression is evaluated "locally", then the result is translated to BSON and "that" is what is executed on the server.

    Point in short is you cannot pass a "BSON field expression" into a "JavaScript function" or other local expression because that is not what actually happens when the statement is evaluated.