MongoDB: parseFloat for string field in aggregate function ($ avg)

I am storing some data in Mongo which contains an arbitrary field. This field is stored as a string, but can contain binary data, integer, float, or whatever (before the application and another "Type" field). Anyway, assuming that I know for sure that the documents I am querying store floating values ​​in this field, entered as a string, I want to know the average of those values ​​over a specific date range. Unfortunately, according to the $ avg documentation , it ignores any values ​​that are not numeric. Is there a way to force parseFloat or something similar to convert the document value on the fly to appease the $ avg operator?

Example of document structure:

{
    "_id": ObjectId("540f4e29f287300b9097663d"),
    "DateReceived": ISODate("2014-09-09T18:59:53.717Z"),
    "Message": {
        "Version": 1,
        "Source": {
            "Device": "MS02166",
            "Application": "Performance Counter",
            "Category": "Disk - Reads/sec",
            "OriginDate": ISODate("2014-09-09T18:59:51.256Z"),
            "Level": 2
        },
        "PayloadText": "0"
    }
}

      

Field I averaging on equals Message.PayloadText

(in this example it is 0, but there are non-zero documents)

The aggregation pipeline request I was able to create is the following:

[{
    "$match": {
        "Message.Source.Application": "Performance Counter"
    }
}, {
    "$match": {
        "Message.Source.Category": "Processor"
    }
}, {
    "$match": {
        "Message.Source.Level": 2
    }
}, {
    "$match": {
        "Message.Source.Device": "MS02166"
    }
}, {
    "$match": {
        "DateReceived": {
            "$gte": ISODate("2014-09-14T07:00:00Z"),
            "$lt": ISODate("2014-09-15T07:00:00Z")
        }
    }
}, {
    "$group": {
        "_id": {
            "hour": {
                "$hour": "$DateReceived"
            }
        },
        "AvgUsage": {
            "$avg": "$Message.PayloadText"
        },
        "MinUsage": {
            "$min": "$Message.PayloadText"
        },
        "MaxUsage": {
            "$max": "$Message.PayloadText"
        }
    }
}]

      

I've tried doing something like "$avg": "parseFloat($Message.PayloadText)"

and to "$avg": "$parseFloat($Message.PayloadText)"

no avail. Oddly enough, the $ min and $ max DO operators produce meaningful results (examples of results below).

{ "_id" : { "hour" : 7 }, "AvgUsage" : 0, "MinUsage" : "0", "MaxUsage" : "9.37442" }
{ "_id" : { "hour" : 8 }, "AvgUsage" : 0, "MinUsage" : "0", "MaxUsage" : "9.37442" }
{ "_id" : { "hour" : 9 }, "AvgUsage" : 0, "MinUsage" : "0", "MaxUsage" : "9.37442" }
{ "_id" : { "hour" : 10 }, "AvgUsage" : 0, "MinUsage" : "0", "MaxUsage" : "9.858578" }
{ "_id" : { "hour" : 11 }, "AvgUsage" : 0, "MinUsage" : "0", "MaxUsage" : "9.999424" }
{ "_id" : { "hour" : 12 }, "AvgUsage" : 0, "MinUsage" : "0", "MaxUsage" : "9.999424" }
{ "_id" : { "hour" : 21 }, "AvgUsage" : 0, "MinUsage" : "0", "MaxUsage" : "9.999424" }
{ "_id" : { "hour" : 16 }, "AvgUsage" : 0, "MinUsage" : "0", "MaxUsage" : "9.37442" }
{ "_id" : { "hour" : 15 }, "AvgUsage" : 0, "MinUsage" : "0", "MaxUsage" : "9.37442" }
{ "_id" : { "hour" : 23 }, "AvgUsage" : 0, "MinUsage" : "0", "MaxUsage" : "9.37442" }
{ "_id" : { "hour" : 18 }, "AvgUsage" : 0, "MinUsage" : "0", "MaxUsage" : "94.02982" }
{ "_id" : { "hour" : 0 }, "AvgUsage" : 0, "MinUsage" : "0", "MaxUsage" : "9.37442" }
{ "_id" : { "hour" : 20 }, "AvgUsage" : 0, "MinUsage" : "0", "MaxUsage" : "9.37442" }
{ "_id" : { "hour" : 22 }, "AvgUsage" : 0, "MinUsage" : "0", "MaxUsage" : "98.48484" }
{ "_id" : { "hour" : 13 }, "AvgUsage" : 0, "MinUsage" : "0", "MaxUsage" : "9.37442" }
{ "_id" : { "hour" : 17 }, "AvgUsage" : 0, "MinUsage" : "0", "MaxUsage" : "98.76543" }
{ "_id" : { "hour" : 14 }, "AvgUsage" : 0, "MinUsage" : "0", "MaxUsage" : "97.18308" }
{ "_id" : { "hour" : 19 }, "AvgUsage" : 0, "MinUsage" : "0", "MaxUsage" : "9.37442" }
{ "_id" : { "hour" : 1 }, "AvgUsage" : 0, "MinUsage" : "0", "MaxUsage" : "9.37442" }
{ "_id" : { "hour" : 4 }, "AvgUsage" : 0, "MinUsage" : "0", "MaxUsage" : "9.37442" }

      

+3


source to share


1 answer


You need to store the number if you want to get the average. There are no type conversion functions available that can map from the string representation of a number to a number. $min

and $max

work because there is an ordering defined for each BSON type (including strings) and between the different BSON types, so MongoDB can always find the maximum value of any field.



+4


source







All Articles