0

I'm using the latest (at the time of writing) version (2.8) of the C# MongoDb driver. I am using it from F#. I want to get the min and max values of a field.

There doesn't appear to be much out there concerning how to use MongoDb (recent version) from F# so I apologize if I have missed something.

The only thing I could get to build is the following

        let client = new MongoClient(connString)
        let db = client.GetDatabase("AirQuality")
        let col = db.GetCollection<ReadingValue>("ReadingValue")
        let toDictionary (map : Map<_, _>) : Dictionary<_, _> = Dictionary(map)

        let minb = ["$min", "$ReadingDate"] |> Map.ofList |> toDictionary
        let maxb = ["$max", "$ReadingDate"] |> Map.ofList |> toDictionary
        let grpb = 
            [
                "_id", null
                "min", minb
                "max", maxb
            ] |> Map.ofList |> toDictionary

        let aggb = ["$group", grpb] |> Map.ofList |> toDictionary
        let doc = new BsonDocument(aggb)
        let pl = new BsonDocumentPipelineStageDefinition<ReadingValue,string>(doc)
        let epl = new EmptyPipelineDefinition<ReadingValue>()
        let finalPipeline = epl.AppendStage(pl)

        use result = col.Aggregate(finalPipeline)

But it raises a run time error Cannot deserialize a 'String' from BsonType 'Document'.

As an aside, I am quite surprised at how awkward it is to use MongoDb from F#.

Post Close Edit:

This question is about how to accomplish the task in F#. The question linked to caters to some other language (probably mongo shell). Using those techniques (as far as I am aware) is not possible in F#.

Chechy Levas
  • 2,206
  • 1
  • 13
  • 28

2 Answers2

1

You can at least simplify the construction of your dictionaries using the dict function:

let grpb =
    dict [
        "_id", null
        "min", dict ["$min", "$ReadingDate"]
        "max", dict ["$max", "$ReadingDate"]
    ]
let aggb = new BsonDocument(dict ["$group", grpb])
Tarmil
  • 11,177
  • 30
  • 35
0

I got it to work with this

    type MinMax = {_id:obj; min:string; max:string}

    let client = new MongoClient(connString)
    let db = client.GetDatabase("AirQuality")
    let col = db.GetCollection<ReadingValue>("ReadingValue")
    let toDictionary (map : Map<_, _>) : Dictionary<_, _> = Dictionary(map)

    let minb = ["$min", "$ReadingDate"] |> Map.ofList |> toDictionary
    let maxb = ["$max", "$ReadingDate"] |> Map.ofList |> toDictionary
    let grpb = 
        [
            "_id", null
            "min", minb
            "max", maxb
        ] |> Map.ofList |> toDictionary

    let aggb = ["$group", grpb] |> Map.ofList |> toDictionary |> (fun x -> new BsonDocument(x))

    let pl = new BsonDocumentPipelineStageDefinition<ReadingValue,MinMax>(aggb)

    let epl = new EmptyPipelineDefinition<ReadingValue>()
    let finalPipeline = epl.AppendStage(pl)
    use result = col.Aggregate(finalPipeline)
    let minMax = result.ToList() |> Seq.head

But I think this is ugly. Is there not a simpler way?

Chechy Levas
  • 2,206
  • 1
  • 13
  • 28