I am attempting to use the C# drivers to recreate a $search stage which I have written manually as a BSON document in Mongo Compass, where it is working exactly has expected. However, I am getting unexpected behaviour/type restrictions when attempting to us SearchDefinitionBuilder.Equals
as the drivers only allow for data types of boolean, numeric, ObjectId and date which is unexpected as the Atlas Search documentation for equals
clearly states that this operator can match against strings as long as they are indexed with the Atlas Search token type as mine are (see my search index below).
When I attempt to use a TField
of type string
with the Equals
method I get the error:
The type ‘string’ must be a non-nullable value type in order to use it as parameter ‘TField’ in the generic type or method 'SearchDefinitionBuilder.Equals(Expression<Func<LegalPerson, TField>>, TField, SearchScoreDefinition)'CS0453
Similarly, if I type to use a TField
of type enum
(in my case Entity.SubType.Company
which is backed by and stored as the data type Int32
and a value of 2
I get the error:
The type ‘Vaiie.Onboard.Api.Models.Entity.SubType’ cannot be used as type parameter ‘TField’ in the generic type or method ‘SearchDefinitionBuilder.Equals(Expression<Func<LegalPerson, TField>>, TField, SearchScoreDefinition)’. There is no boxing conversion from ‘Vaiie.Onboard.Api.Models.Entity.SubType’ to ‘System.IComparable<Vaiie.Onboard.Api.Models.Entity.SubType>’.CS0315
For example:
As you will see from my search index and $search stage samples below, the use of exists
on these fields with these data types works exactly as hoped when I form this $search BSON document manually in Compass and my results include all expected documents however, I seem unable to build up this same $search stage via the C# drivers due to these type restrictions.
Am I doing something wrong, or is this a bug/oversight with the drivers?
Sample Document:
``{
“_t”: [
“Profile”,
“LegalPerson”
],
“status”: 2,
“subType”: 2,
“contactDetails”: {
“email”: “info@acme.co.uk”,
“countryCode”: 44,
“subscriberNumber”: “7797812345”
},
“countryOfRegistration”: “GB”,
“registrationNumber”: “123456789”,
“name”: “Acme Corporation UK”
}`
Search Index:
"mappings": {
"dynamic": false,
"fields": {
"_t": {
"type": "token",
"normalizer": "none"
},
"subType": {
"type": "number",
"representation": "int64",
"indexIntegers": true
},
"status": {
"type": "number",
"representation": "int64",
"indexIntegers": true
},
"contactDetails": {
"type": "document",
"fields": {
"email": {
"type": "string",
"analyzer": "basicEmailAddressAnalyzer"
}
}
},
"name": {
"type": "string",
"analyzer": "lucene.standard"
},
"countryOfRegistration": {
"type": "token",
"normalizer": "lowercase"
},
"registrationNumber": {
"type": "string",
"analyzer": "lucene.keyword"
}
}
},
"analyzers": [
{
"name": "basicEmailAddressAnalyzer",
"tokenizer": {
"type": "uaxUrlEmail"
}
}
]
}`
`$search` Stage:
`/**
* index: The name of the Search index.
* text: Analyzed search, with required fields of query and path, the analyzed field(s) to search.
* compound: Combines ops.
* span: Find in text field regions.
* exists: Test for presence of a field.
* near: Find near number or date.
* range: Find in numeric or date range.
*/
{
index: "profileLegalPerson",
compound: {
filter: [
// LegalPerson based Dossiers
{
equals: {
path: "_t",
value: "LegalPerson"
}
},
// Company based LegalPersons
{
equals: {
path: "subType",
value: 2
}
},
// In Draft or Live state
{
in: {
path: "status",
value: [1, 2]
}
}
],
should: [
{
text: {
path: "contactDetails.email",
query: "info@acme.co.uk",
score: {
boost: {
value: 4
}
}
}
},
{
text: {
path: "name",
query: "acme",
score: {
boost: {
value: 2
}
}
}
},
{
text: {
path: "registrationNumber",
query: "123456789",
score: {
boost: {
value: 10
}
}
}
},
{
equals: {
path: "countryOfRegistration",
value: "GB"
}
}
],
minimumShouldMatch: 1
}
}`