MongoDb and F#: How to select distinct values? - mongodb

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 select the distinct values of a field in a collection.
From this old question, the following does not work:
let client = new MongoClient(connString)
let db = client.GetDatabase("AirQuality")
let col = db.GetCollection<ReadingValue>("ReadingValue")
let res = col.DistinctAsync<string>("SensorName","{}")
The type string is not compatible with the type FieldDefinition<ReadingValue,string>.
From this answer, the following does not work either
let fd : FieldDefinition<ReadingValue, string> = "" :> FieldDefinition<ReadingValue, string>

In C# you can implicitly convert from string to FieldDefinition<T> (class implements implicit operator). Since types conversion works in a different way in F# you can use StringFieldDefinitionClass
let field = new StringFieldDefinition<ReadingValue, string>("SensorName")
let result = col.Distinct<string>(field, Builders<ReadingValue>.Filter.Empty)

Related

Optional join in Diesel

I want to add conditional filter on joined table:
let query = first_table::table.into_boxed();
if Some(filter_string) = filter {
// ERROR: inner_join() generates value of new type,
// cannot assign it to boxed query
query = query
.inner_join(joined_table::table.on(...))
.filter(jointed_table::dsl::string_field.eq(filter_string))
}
// joined_table actually is not required here
let result = query.select(first_table::all_columns).load(...)?;
Is there a way to downcast type of modified query into original one's, or may be there's another way to do that without copy-pasting final chain .select().load() into condition?

How to Filter Regular expression in MongoDB with F#

I've tried quite a few different ways of doing this and ultimately I would like to have multiple find filters together.
So - for example, one way would be like https://www.codeproject.com/Articles/1228421/Dynamic-high-performance-Query-builder-for-MongoDB
Trying to build the following C# code in F# ( and converting to my code )
Builders<CustomerGrid>.Filter.Regex(u => u.company,
new BsonRegularExpression(companyColumnText + "*", "I"))
I have tried
let filter1 = Builders<PostDataItem>.Filter.Regex(fun n -> n.reference1,new BsonRegularExpression("1002\d{5}"))
and ( with brackets around field definition )
let filter1 = Builders<PostDataItem>.Filter.Regex((fun n -> n.reference1),new BsonRegularExpression("1002\d{5}"))
Another way of looking at it is to break down the parameters
let fd: FieldDefinition<PostDataItem> = // ?? field = reference1
let re: BsonRegularExpression = new BsonRegularExpression("1002\d{5}")
let filter1 = Builders<PostDataItem>.Filter.Regex(fd,re)
It seems that if I could figure out how to build the field definition then it might work.
You're close. The only problem I see is that the LINQ expression has to have a return type of Object. This happens implicitly in C#, but in F# you have to explicitly cast it:
let filter1 =
Builders<PostDataItem>
.Filter
.Regex(
(fun n -> n.reference1 :> obj),
BsonRegularExpression("1002\d{5}"))
(IMHO, this is just a bit of C# bias baked into their API. Hopefully they’ll fix it one day.)

Kotlin equivalent of %# in swift

i am new to kotlin.
In swift i can do :
let endpoint = "categories/" + "%#/issues/"
let number = "4"
let finalstring = String(format: endpoint, number)
The final output of the string will be : categories/4/issues/ as a string .
I have looked at string format in kotlin but it's only work afterwards meaning that i can't define a template for my string and fill it later.
var value1 = "categories/"
var value2 = 4
var value3 = "/issues/"
println(java.lang.String.format("%s%d%s", value1, value2, value3))
This give me the same result but it's mean that i have to manualy write the end of the string.
What i want to do i to have a template for my string in a Road file.
Then complet my string at the run time. The probleme is that the part of my string that i want to complete is in the middle of the string.
Of course i can use substring and remplace but i am looking for a clean way to do it as in swift.
Thanks for helping.
One possible option would be to define a local function that does the formatting:
fun requestString(number: Int) = "categories/$number/issues/"
val finalString = requestString(4)
You can create your format string up front with all the constant parts, and with relevant placeholders (like %d for numbers) (more info in the javadoc).
Later, use the regular Java String.format() later with the parameters:
// define this constant up front
val format = "categories/%d/issues/"
// and then later:
val categoryId = 4
println(String.format(format, categoryId))
You already have the answer right there in your example, you just have to put it together.
String.format takes %s as placeholder for a String or %d for a number (and many more placeholder options).
So your template string would be: "categories/%d/issues/". To format it you use:
val format = "categories/%d/issues/"
val number = 4
val string = String.format(format, number)
About interpolation vs formatting, they can be used in different situations.
If you have the template string available in source code then you would use interpolation:
val string = "categories/${category.id}/issues/"
But when you have no control over the string, because it comes from an external source (such as a file), then you would have to use the formatting.

Can I create a Date object from a predefined string (typescript)?

I have a value returned in a string (numbers separated by commas) and I'd like to make a Date object out of it. It looks like this is not possible, can someone confirm and/or suggest me a solution.
This does not work :
let dateString='2017,3,22,0';
let dateFromString = new Date(dateString);
This works though (when I pass a list of numbers) :
let dateFromString = new Date(2017,3,22,0);
And this works also :
let dateString = '2008/05/10 12:08:20';
let dateFromString = new Date(dateString);
The goal would be to create a Date object from a uniform string. Is that possible ?
Can I create a Date object from a predefined string, which has only one type of separator (comma, colon, slash or whatever) ?
If your environment is compatible with ES6 (eg. Babel, TypeScript, modern Chrome/Firefox etc), you can use the string's .split(',') and decompose the array into arguments like the following:
const dateString = '2017,3,22,0';
const date = new Date(...dateString.split(',')); // date object for 2017/03/22
ES5 compatible version:
var dateString = '2017,1,2,0';
var date = new (Function.prototype.bind.apply(Date, [null].concat(dateString.split(','))));
As for how the .bind.apply method works with new, you can take a look at Use of .apply() with 'new' operator. Is this possible?
Note: Thanks to the two comments below for spotting my errors 👍

Shortest syntax for Entity Framework compatible POCO

I need F# to work with Entity Framework seemlesly. I am trying to adapt example from here: https://blogs.msdn.microsoft.com/visualstudio/2011/04/04/f-code-first-development-with-entity-framework-4-1/
The problem is that record declaration is so scary there that it is just unacceptable for me.
type public Car() =
let mutable m_ID : int = 0
let mutable m_name : string = ""
[<Key>]
member public this.ID with get() = m_ID
and set v = m_ID <- v
member public this.Name with get() = m_name
and set v = m_name <- v
I have tried CLIMutable in such a way:
module Program
[<CLIMutable>]
type Car = {
Name:string
}
let c = new Car(Name = "Honda")
It results in error: "No contructors are available for the type 'Car'".
As I understand this answer might be an explanation:
https://stackoverflow.com/a/28845368/585819
I also tried things like:
[<CLIMutable>]
type Car =
{
ID:int
} member this.Name = ""
The error is the same. I feel really disappointed. Can somebody help with this?
The CLIMutable attribute does not have any impact on F# use-sites. The added default constructor is inaccessible from F# user-code and so are mutable properties. If you want to use EFs change tracking (from within F#), records are not a good choice (because you can't change it unless you declare all fields mutable).
If possible consider using e.g. the SQL Provider. On the other hand e.g. Dapper supports serializing/deserializing POCOs and thusly F# records.
As the record looks immutable from F# perspective, regular construction applies:
let c = { Name = "Honda" }
or (to disambiguate, if you also have e.g. type Person = { Name : string })
let c = { Car.Name = "Honda" }
let c : Car = { Name = "Honda" }
let c = { Name = "Honda" } : Car
Here is what seems to be working for me. This is not a record but class. Also it probably could not be named POCO.
//file DataModel.fs
module DataModel
open System.ComponentModel.DataAnnotations
open System.Data.Entity
type Car()=
[<Key>]
member val Id = 0 with get,set
member val Name = "" with get,set
type public CLCars() =
inherit DbContext()
member val Cars: DbSet<Car> = base.Set<Car>() with get,set
//file Program.fs
module Program
open DataModel
let db = new CLCars()
let c = new Car(Name="Honda")
db.Cars.Add(c) |> ignore
db.SaveChanges() |> ignore