How to find matching 'StartsWith' documents on classless MongoDB using C# driver - c#

I have documents:
{"handler":"north"}
{"handler":"south"}
{"handler":"west"}
{"handler":"east"}
I want to find a matching handler from a given string input, e.g. "westtown" and expects the handler will be "west".
Please help, my code below does not work.
String inputstring = "westtown";
IMongoCollection<BsonDocument> collection = null;
List<BsonDocument> pages = null;
try
{
collection = db.GetCollection<BsonDocument>("handlers");
pages = await collection.Find(x => (inputstring.StartsWith(x["handler"].AsString))).ToListAsync<BsonDocument>();
}
...
I use classless scheme, so I use BsonDocument on the dynamic.

AFAIK, In MongoDB you can find it with $where operator like this:
{ $where: "'westtown'.startsWith(this.handler)" }
So, I think in c# you can do it with something like this:
var filter =
new BsonDocument(
new Dictionary<string, BsonValue>
{
{
"$where",
new BsonString("'westtown'.startsWith(this.handler)")
}
});
var result = col.Find(filter).ToList();

Related

How to sort dynamically in mongodb

I have a "sort" query parameter. This maybe looking like this:
?sort=-name,+number
Now I want to read this and build a sort query for the c# MongoDB-Driver.
I thought of something like this:
var sortByList = parameters.Sort?.Split(',');
foreach (var sortBy in sortByList)
{
if (sortBy.StartsWith('-'))
// add to sort query decending ?!?
else
// add to sort query ascending ?!?
}
The only way I found so far is to build a string like "{name:-1, number:1}" and give this to the .Sort-method. But so I have build to build many strings that I really don't need.
Isn't there a way to do something like:
var sortDefinition = new SortDefintion();
var sortByList = parameters.Sort?.Split(',');
foreach (var sortBy in sortByList)
{
if (sortBy.StartsWith('-'))
sortDefinition.Add(sortBy.Substring(1), -1);
else
sortDefinition.Add(sortBy.Substring(1), 1);
}
return db.GetCollection<BsonDocument>("sortTest").Sort(sortDefintion).ToList();
You can solve it like this:
var bldr = Builders<BsonDocument>.Sort;
var sortDefinitions = sortByList.Select(x =>
{
SortDefinition<BsonDocument> sortDef;
var propName = x.Substring(1);
if (x.StartsWith("-"))
sortDef = bldr.Descending(propName);
else
sortDef = bldr.Ascending(propName);
return sortDef;
});
var sortDef = bldr.Combine(sortDefinitions);
return db
.GetCollection<BsonDocument>("sortTest")
.Find(Builders<BsonDocument>.Filter.Empty)
.Sort(sortDef)
.ToList();
Above code uses a Linq Select to create a SortDefinition<BsonDocument> for each string in the list and combines these definitions into a single sort definition afterwards. This sort definition is then applied to the Find.

Insert collection into List from MongoDB

I try to get all data from collection into MongoDB server using C# driver.
The idea is connect to the server and get all collection than insert into list of class.
List<WatchTblCls> wts;
List<UserCls> users;
List<SymboleCls> syms;
public WatchTbl()
{
InitializeComponent();
wts = new List<WatchTblCls>();
users = new List<UserCls>();
syms = new List<SymboleCls>();
}
public async void getAllData()
{
client = new MongoClient("mongodb://servername:27017");
database = client.GetDatabase("WatchTblDB");
collectionWatchtbl = database.GetCollection<WatchTbl>("Watchtbl");
collectionUser = database.GetCollection<UserCls>("Users");
collectionSymbole = database.GetCollection<SymboleCls>("Users");
var filter = new BsonDocument();
using (var cursor = await collectionWatchtbl.FindAsync(filter))
{
while (await cursor.MoveNextAsync())
{
var batch = cursor.Current;
foreach (var document in batch)
{
wts.Add(new WatchTblCls(document["_id"], document["userId"], document["wid"], document["name"], document["Symboles"]));
}
}
}
}
I get this error under
wts.Add(new WatchTblCls(document["_id"], document["userId"], document["wid"], document["name"], document["Symboles"]));
Cannot apply indexing with [] to an expression of type 'WatchTbl'
I don't understand the reason behind using WatchTbl and WatchTblCls both together. Is WatchTblCls a model for the entity WatchTbl here? Im not sure.
In any case. If you go for aggregation and want to convert WatchTbl collection to WatchTblCls list, your desired solution might look like the following. I don't know the defiitions of the classes so I'm assuming:
var client = new MongoClient("mongodb://servername:27017");
var database = client.GetDatabase("WatchTblDB");
var collectionWatchtbl = database.GetCollection<WatchTbl>("Watchtbl");
var collectionUser = database.GetCollection<UserCls>("Users");
var collectionSymbole = database.GetCollection<SymboleCls>("Users");
var list = collectionWatchtbl.AsQueryable().Select(x => new WatchTblCls() {
id = x.id,
userId = x.userId,
.....
});
If you can use the same WatchTbl class and still want to load the full collection to a local List (which is definitely not a good idea):
List<WatchTbl> list = await collectionWatchtbl.Find(x => true).ToListAsync();

DistinctAsync against array sub documents with MongoDB C# 2.0 driver

In MongoDB 3.0 with the C# 2.0 driver, how do you get a distinct list of values using DistinctAsync from a document's array of sub documents?
I'm looking for the C# equivalent of this in the shell:
db.cars.distinct("parts.name", {"make":"Ford"})
After admitting defeat, I resorted to this shell-ish code:
var distinctParts = await db.RunCommandAsync<BsonDocument>(new BsonDocument {
{ "distinct", "cars"},
{"key", "parts.name"},
{"query", new BsonDocument { { "make", "Ford" }} } });
Thanks!
Something like this should work:
var filter = new MongoDB.Driver.ExpressionFilterDefinition<CARS_TYPE>(x => x.make == "ford");
var distinctParts = await cars_collection.DistinctAsync<string>("parts.name", filter);

Having trouble with a very basic search -- no results

I have Elasticsearch up and running. Using Sense within Marvel, I am able to get a result, with this query:
GET _search
{
"query": {
"query_string": {
"query": "massa"
}
}
}
My c# code, trying to recreate the above:
var node = new Uri("http://localhost:9200");
var settings = new ConnectionSettings(node).SetDefaultIndex("mediaitems");
var client = new ElasticClient(settings);
var results = client.Search<stuff>(s => s
.Query(qs => qs.QueryString(q => q.Query("massa"))));
var d = results.Documents;
But unfortunately I'm not getting any results, nothing in "results.Documents". Any suggestions? Maybe a way to see the generated json? What is the simplest way to just query everything in an index? Thanks!
Even though your search results are going to be mapped to the proper type because you are using .Search<stuff>, you still need to set the default type as part of your query.
var node = new Uri("http://localhost:9200");
var settings = new ConnectionSettings(node).SetDefaultIndex("mediaitems");
var client = new ElasticClient(settings);
var results = client.Search<stuff>(s => s
.Type("stuff") //or .Type(typeof(stuff)) if you have decorated your stuff class correctly.
.Query(qs => qs.QueryString(q => q.Query("massa"))));
var d = results.Documents;
Additionally, your results response contains a ConnectionStatus property. You can interrogate this property to see the Request and Response to/from Elasticsearch to see if your query is being executed as you expect.
Update: You can also set a default type the index settings as well.
var settings = new ConnectionSettings(node).SetDefualtIndex("mediaitems");
settings.MapDefaultTypeIndices(d=>d.Add(typeof(stuff), "mediaitems");
You can also check nest raw client
var results = client.Raw.SearchPost("mediaitems", "stuff", new
{
query = new
{
query_string = new
{
query = "massa"
}
}
});
You can get the values of search request URL and JSON request body as under:
var requestURL = response.RequestInformation.RequestUrl;
var jsonBody = Encoding.UTF8.GetString(response.RequestInformation.Request);
You can find other useful properties in RequestInformation for debugging.

Breeze work-around for multi valued property queries

I'm trying to assemble ad-hoc queries to Breeze.
I have a physician.contact.addresses relationship.
When I try:
myPred = new pred('contact.addresses.street1', op.StartsWith, "a");
And execute it I get:
"The parent value for a property access of a property 'Addresses' is not a single value. Property access can only be applied to a single value."
To try a work-around I've tried parsing out those many-relationships and am passing it to the breeze controller in .withParameters like this:
var criteriaStr = toManyArray.length ? ko.utils.stringifyJson(toManyArray) : "";
query = query.withParameters({ searchParms: criteriaStr });
where toManyArray is an array of fieldName:value pairs.
on the controller side:
[HttpGet]
public IQueryable<Physician> Physician(string searchParms = null)
{
if (searchParms != null)
{
var ser = new JavaScriptSerializer();
var searchCritAry = ser.Deserialize<String[]>(searchParms);
foreach (var aryItem in searchCritAry)
{
// aryItem looks like this:
// f_str_street_from_addresses:a
var predEnt = aryItem.Split(':')[0].Split('_')[4];
var predField = aryItem.Split(':')[0].Split('_')[2];
var predVal = aryItem.Split(':')[1];
switch (predEnt)
{
case "addresses":
switch (predField)
{
case "street":
//physPool =
_contextProvider.Context.Physicians
.Where(p => p.Contact.Addresses.Any(a => a.Street1.StartsWith(predVal)));
break;
case "street2":
//physPool =
_contextProvider.Context.Physicians
.Where(p => p.Contact.Addresses.Any(a => a.Street2.StartsWith(predVal)));
break;
}
break;
}
}
// here I want to combine the .Where clauses from above with the breeze preds
return _contextProvider.Context.Physicians;
}
return _contextProvider.Context.Physicians;
}
It's not working and only returning a selection using the predicates that are passed in the normal way through Breeze's query. I don't see how to pass the filtered IQueryable to Breeze's _contextProvider.
Thanks for any suggestions.
Take a look at the new "any/all" support in Breeze ( as of version 1.4.7). Some examples may be found here: http://www.breezejs.com/documentation/query-examples
You can construct your query/predicate like this:
var pred = new Breeze.Predicate('contact.addresses', "any", 'street1', op.StartsWith, "a");
var query = EntityQuery.from("Physicians").where(pred);
or simply
var query = EntityQuery.from("Physicians")
.where("contact.addresses", "any", "street1", "startsWith", 'a')
You may want to add an expand if you want the contact and address information sent down as well.
query = query.expand("contact.addresses");
If you have a need for nested any/all expressions you may need to add the following configuration to your BreezeController to determine just how deep you want to allow the expressions to go (2 in the example below):
[BreezeController(MaxAnyAllExpressionDepth = 2)]

Categories

Resources