I've a collection with orders, each with an OrderId field of type int32. I would like to filter the collecting and get all orders where the OrderId contains e.g. 123. For instance the following OrderIds must match:
123
9912399
99123
The following raw mongo filter works:
{ $where: "/^.*123.*/.test(this.OrderId)" }
How can this be expressed in the C# Mongo client or something different that does the job?
I'm not able to use the below code, as it seems to only work in string fields:
Builders<Order>.Filter.Regex(x => x.OrderId, new BsonRegularExpression("123"))
ideally you should store a string version of the order id in your documents. in case that's not an option you can do the following aggregation pipeline:
var res = await collection
.Aggregate()
.AppendStage<object>("{ $set : { orderIdString : { $toString : '$OrderId' } } }")
.Match(Builders<object>.Filter.Regex("orderIdString", "/123/"))
.AppendStage<object>("{ $unset : 'orderIdString' }")
.As<Order>()
.ToListAsync();
I don't think you can generate $where via typed builders. So, as it was mentioned above, the only option you have is to create a filter from a raw MQL like below:
var coll = db.GetCollection<Order>("coll");
var result = coll.Find("{ $where: '/^.*123.*/.test(this.OrderId)' }").ToList();
Did you try using:
x => x.OrderId.ToString()
instead of
x => x.Orderid
You can use Filter.Regex to achieve the desired behavior:
var valueToFilterBy = "123"
var filter = Builders<Order>.Filter.Regex(nameof(Order.Id), new BsonRegularExpression($".*{valueToFilterBy}.*"));
var data = await collection.FindAsync(filter).ToListAsync();
Related
i use mongodb driver in C# for finding and ... records. i want to use json string query to find records.
the below line is my code for finding the data.
var res = collection.Find<object>("{ longitude:49.3815270248724 }").ToList();
but i have an error on this line with this text: "MongoDB.Bson.BsonSerializationException: 'Unknown discriminator value 'record'.'"
but i test this query in "studio 3T for MongoDB". and i can fetch records in "Studio". my query in "studio ..." is: db.records.find({longitude:49.3815270248724})
what can i do for this problem!!
You can use one of these
Finding by filter (full method):
// Coordinate is a class
public async Task<List<Coordinate>> Get(double longitude)
{
var filter = new BsonDocument("longitude", longitude);
var list = await Collection.Find(filter).ToListAsync();
return list;
}
Filter record by Where Keyword:
var list = collection
.AsQueryable()
.Where(e => e.longitude == 49.3815270248724)
.ToList();
Using the C# NEST API on Elasticsearch:
var searchResults = client.Search<Product>(s => s
.Index(Constants.ElasticSearchIndex)
.Query(q => q
.Raw(jsonRequest)
)
);
The query is supposed to run on the /sc_all/ index, but it runs on /sc_all/product/ index (which doesn't exist - /product/ seems to be added because of the Search since T = product).
If I do like this, /product/ is replaced with the value of the constant, i.e. /sc_all/product/ => /sc_all/constant_value/:
var searchResults = client.Search<Product>(s => s
.Index(Constants.ElasticSearchIndex)
.Type(Constants.ElasticSearchType)
.Query(q => q
.Raw(jsonRequest)
)
);
What should I do if I just want to query /sc_all/ and nothing else?
Thanks!
Json request:
"{\"filtered\": {\"query\": {\"match_all\": { }},\"filter\": {\"nested\" : {\"path\" : \"products\",\"filter\": {\"nested\" : {\"path\" : \"products.da\",\"filter\": { \"bool\": { \"must\": [{\"query\": {\"query_string\": {\"default_field\" : \"products.da.content\", \"query\" : \"kildemoes\"}}}]}}}}}}}}, \"from\": 0, \"size\": 100"
You just need to specify to run across all types with .AllTypes()
var jsonRequest = "{ \"match_all\": {} }";
var searchResults = client.Search<Product>(s => s
.Index(Constants.ElasticSearchIndex)
.AllTypes()
.Query(q => q
.Raw(jsonRequest)
)
);
which will generate the following request
POST http://localhost:9200/sc_all/_search
{
"query": { "match_all": {} }
}
Bear in mind that any documents returned will attempt to be deserialized into instances of Product so if you will be targeting multiple different types, you may want to use a common base type or dynamic and additionally, take advantage of covariant search results.
You were using an outdated version client, like 5.x.
I came across the same problem too using 5.x. The second subpath is the document type, which is the _type name of your document and is docs by default. So, the solution I use is to add [ElasticsearchType(Name = "docs")] at the top of my POCO class and the search path will is something like /{indexname}/docs/_search, and it's fine.
I have an object in C# which has a few properties:
// Pseudo class
public class
{
Id;
To;
From;
}
I have alot instances of that class in a Collection. Which could look like this:
object 1:
Id: 1
To: "PathA"
From: "PathB"
object 2:
Id: 2
To: "PathB"
From: "PathC"
object 3:
Id: 3
To: "PathC"
From: "PathA"
Now what I want to do is get all the items from that collections where the value of To doesn't appear in the From in any of the objects. Which would result in the following:
object 1:
Id: 1
To: "PathA"
From: "PathB"
object 2:
Id: 2
To: "PathB"
From: "PathC"
Because the last object with Id: 3 has PathA in the From property, which already exists somewhere in the To property.
How can I do this with a Linq query?
Well, how to go about this problem? First, you could create an index of all the values of To. Then, filter your sequence based on the From property...
Something like:
var tos = new HashSet<string>(collection.Select(item => item.To));
var filtered = collection.Where(item => !tos.Contains(item.From));
You might want to check, if creating a HashSet really works like this, or if you need to construct it differently... but you get the idea. Sets are efficient, if the tos gets rather long, since you will be checking this a lot...
Say your collection of objects is as follows:
var objects = { object1, object2, object3 }
Then you want:
var result = objects.Where(o => !objects.Select(x => x.From).Contains(o.To));
If it concerns a large dataset, it might be smart to cache and store the sub-selection of "From" paths:
var fromPaths = new HashSet<string>(objects.Select(x => x.From));
var result = objects.Where(o => !fromPaths.Contains(o.To))
Firstly, your sample doesn't really match the question-text since all the sample objects have a To corresponding to some other From. But assuming the question-text is right and the sample is wrong:
How about with a group-join:
var query = from obj in collection
join fromObj in collection
on obj.To equals fromObj.From
into objGroup
where !objGroup.Any()
select obj;
Alternatively, build up a set of distinct Froms first:
var distinctFroms = new HashSet<string>(collection.Select(item => item.From));
var query = from obj in collection
where !distinctFroms.Contains(obj.To)
select obj;
var list = collection.Select(c=>c.To).Distinct().ToList();
var result = collection.Where(c=>!list.Contains(c.From)).ToList();
If you join the collection back onto itself using To and From as the respective keys, you can establish which items are "joined" via To/From and exclude them:
var itemsThatAreConnected =
collection.Join(collection, x => x.To, x => x.From, (a,b) => a);
var unconnected = collection.Except(itemsThatAreConnected);
I am working on an ASP.NET MVC application. This application executes a query via JQuery. The result set is returned as JSON from my ASP.NET MVC controller. Before I return the serialized result set, i need to trim it down to only the properties I need. To do this, I'm using a LINQ Query. That LINQ Query looks like the following:
private IEnumerable RefineResults(ResultList<Result> results)
{
// results has three properties: Summary, QueryDuration, and List
var refined = results.Select(x => new
{
x.ID, x.FirstName, x.LastName
});
return refined;
}
When I execute this method, I've noticed that refined does not include the Summary and Duration properties from my original query. I'm want my result set to be structured like:
Summary
QueryDuration
Results
- Result 1
- Result 2
- Result 3
...
At this time, when I execute RefineResults, I get the result list I would expect. However, I can't figure out how to put those entries in a property called "Results". I also don't know how to add the "Summary" and "QueryDuration" properties.
Can someone please point me in the right direction?
Thanks!
private object RefineResults(ResultList<Result> results)
{
// results has three properties: Summary, QueryDuration, and List
var refined = results.Select(x => new
{
x.ID, x.FirstName, x.LastName
});
return new { Results = refined, Summary = results.Summary, QueryDuration = results.QueryDuration };
}
You will probably want to create a specific DTO class for the return value of this function.
I'm trying to figure out how to sort a collection of documents server side by telling the C# driver what the sort order is, but it appears not to support that construct yet.
Is it possible to do this any other way?
You can also do it using the SetSortOrder method on the MongoCursor class:
db["collection"].Find().SetSortOrder(SortBy.Ascending("SortByMe"));
Just to add to Chris's answer, in C# Driver 2.x it is now done with SortBy, SortByDescending, ThenBy & ThenByDescending
collection.Find(bson => true).SortBy(bson => bson["SortByMeAscending"]).ThenByDescending(bson => bson["ThenByMeDescending"]).ToListAsync()
Now it resembles Linq even more.
http://mongodb.github.io/mongo-csharp-driver/2.0/reference/driver/crud/reading/#sort
For async methods:
var filter = Builders<BsonDocument>.Filter.Empty;
var sort = Builders<BsonDocument>.Sort.Ascending("time");
collection.FindAsync(filter, new FindOptions<BsonDocument, BsonDocument>()
{
Sort = sort
});
Simple usage of api in MongoDB.Driver 2.5.0
var client = new MongoClient("mongodb://localhost:27017");
var database = client.GetDatabase("Blog");
var list = database.GetCollection<BlogPost>("BlogPost")
.Find(e => e.Deleted == false)
.SortByDescending(e => e.CreatedOn)
.Limit(20)
.ToList();
Note that to sort on multiple fields use this:
db["collection"].Find().SetSortOrder(SortBy.Ascending("SortByMe").Descending("AndByMe");
If you want to use linq:
From the documentation: (http://docs.mongodb.org/ecosystem/tutorial/use-linq-queries-with-csharp-driver/)
var query=
(from c in collection.AsQueryable<C>()
orderby c.X
select c)
foreach (var d in query)
{
// process your documents
}
If you want you can also limit the results:
var query=
(from c in collection.AsQueryable<C>()
orderby c.X descending
select c).Take(1);
Just remember to have an index on the field you are sorting by : ]
It seems the way to do this using the existing C# driver is as follows:
db["collection"].Find(new Document().Append("query",
new Document()).Append("orderby",
new Document().Append(name:1).Append(age,-1)));
Which I was turned on to by Sam Corder here
You can apply sort with SortDefinition like this:
FilterDefinition<User> filter = Builders<User>.Filter.Eq(a => a.Deleted , false);
SortDefinition<User> sort = Builders<User>.Sort.Descending(a => a.Id);
List<User> result = _dbContext.Users.Find(filter).Sort(sort).Limit(10).ToList();
#DmitryZyr's answer for FindAsync was not working. This one did however.
var sortDefinition = new SortDefinitionBuilder<ImmutableLog>().Descending("date");
var findOptions = new FindOptions<ImmutableLog>() {Sort = sortDefinition};
await this.Collection.FindAsync(new BsonDocument(), findOptions);
I'm currently using the API version MongoDB.Driver 2.8.1.
Here is my method that I call to return a list of objects with Descending sorting, if it is required:
public static IEnumerable<TEntity> GetDocumentsForCollection(
IMongoDatabase database,
string collectionName,
FilterDefinition<TEntity> query,
string databaseCollectionKeyToSortOnDescending)
{
var _mongoSettings = new MongoCollectionSettings();
_mongoSettings.GuidRepresentation = GuidRepresentation.Standard;
var _collection = database.GetCollection<TEntity>(collectionName, _mongoSettings);
if (string.IsNullOrEmpty(databaseCollectionKeyToSortOnDescending))
{
return _collection.Find(query).ToList();
}
return _collection.Find<TEntity>(query).Sort(Builders<TEntity>.Sort.Descending(databaseCollectionKeyToSortOnDescending)).ToList();
}
I'm doing this in JavaScript since I don't know C#, but it should have equivalent syntax with the C# driver.
If your query looked like:
db.c.find({"foo" : "bar"})
and you want to sort by "baz" ascending, wrap your query in a "query" field and add an "orderby" field:
db.c.find({"query" : {"foo" : "bar"}, "orderby" : {"baz" : 1}})
For descending sort, use -1.