I'm using official Mongo C# driver. As suggested in answer to one question I'm using the following for the 'like' operator -
Query.Matches("name", "Joe");
My question is how can I achieve the 'NotLike' functionality ?
Assuming you are using the new Query builder in version 1.5, you would do it this way:
var query = Query.Not(Query.Matches("name", "Joe"));
In version 1.5 we also introduced a new typed Query builder, which you could use this way:
var query = Query.Not(Query<C>.Matches(x => x.Name, "Joe"));
Finally, you could also write a LINQ query:
var query = collection.AsQueryable<C>().Where(x => !Regex.IsMatch(x.Name, "Joe"));
Related
I am using Symfony Doctrine Mongodb-odm 1.2 library in the project. group() & reduce() methods are deprecated and no longer available with MongoDB 4.2. My existing code has used these methods to group and pull the MongoDB records using custom reduce logic on the query. Refer the following query:
$customers = $this->createQueryBuilder($business)
->field('pay_status')->equals('unpaid')
->group(['contact' => 0], ['total' => 0])
->reduce(
'function (obj, prev) {
prev.total += obj.total.amount;
prev.contact_data = obj.contact_data;
if (obj.contact) {
prev.contact = obj.contact.$id.str;
}
return prev;
}'
)
->limit(5)
->getQuery()
->execute()
->toArray(false);
This works completely fine with MongoDB 4.0 and returns the result set with top 5 unpaid customers list. Now, I am struggling to find out the replacement for this query using aggregation pipeline which is recommended for MongoDB 4.2.
Can anyone help with the replacement query using aggregation builder methods? I know how to group the result using aggregation stage but not sure how to pull the top 5 customers without reduce() method here. Thanks in advance.
I guess I found the way to query & retrieve the expected result set using aggregation builder without reduce method:
$customers = $this->createAggregationBuilder($business)
->hydrate(false)
->match()
->field('pay_status')->equals('unpaid')
->group()
->field('_id')->expression(['contact_data'=>'$contact_data','contact'=>'$contact'])
->field('total')->sum('$total.amount')
->project()
->field('total')->expression('$total')
->field('contact')->expression('$_id.contact')
->field('contact_data')->expression('$_id.contact_data')
->field('_id')->expression('$$REMOVE')
->sort(['total' => 'desc'])
->limit(5)
->getQuery()
->execute()
->toArray(false);
I am migrating from the mongodb csharp driver 1.10.0 to 2.0.0.
One of the collection I am using is very big and has to fulfill many queries with different filter attributes. That is why I was relying on some index hint statements. With the v1.10 driver it looks like
myCollection.Find(query).SetHint("myIndexName");
I searched the v2 driver api but this hint method seems to be completly removed in the v2 driver. Is there an alternative? How should I do index hints with the v2 driver?
Note: The Solutions provided works for latest mongodb csharp drivers as well
You can use the FindOptions.Modifiers property.
var modifiers = new BsonDocument("$hint", "myIndexName");
await myCollection.Find(query, new FindOptions { Modifiers = modifiers }).ToListAsync();
May I ask why you are using the hint? Was the server consistently choosing the wrong index? You shouldn't need to do this except in exceptional cases.
Craig
Ideally, try to make the query in a way that mongodb optimizer can use the index automatically.
If you are using FindAsync then you will have a property named Hint. Use it like this:
If you have index named "myIndexName" which you want your query should use forcefully, then use like this:.
BsonString bsonString = new BsonString("myIndexName");
cursor = await collection.FindAsync(y => y.Population > 400000000,
new FindOptions<Person, Person>()
{
BatchSize = 200,
NoCursorTimeout = true,
AllowPartialResults = true,
Projection = "{'_id':1,'Name':1,'Population':1}"
Hint = bsonString.AsBsonValue,
}).ConfigureAwait(false);
You can fine BsonString class in MongoDB.Bson
With agregate you can force indice like this:
BsonString bsonString = new BsonString("ix_indice");
var query = this.collection.Aggregate(new AggregateOptions() { Hint = bsonString }).Match(new BsonDocument {..});
If you are using the Linq IQueryable, you can specify the hint (and other options) like this:
BsonDocument hint = new BsonDocument("myFieldName", 1);
// or
BsonDocument hint = new BsonString("myIndexName");
await collection.AsQueryable(new AggregateOptions { Hint = hint })
myFieldName can also reference a complex field, e.g. Metadata.FileName
myIndexName is the name of an index. I prefer to reference the field (first option) directly, instead of an index, for simple cases.
I've ported some of my Entity from JPA to document and now porting some of my queries.
here is the JPA query:
em.createQuery("select distinct c from CustomerImpl c left join fetch c.addresses ca where (:name is null or c.firstName LIKE :name or c.lastName LIKE :name) and (:ref is null or c.externalReference LIKE :ref) and (:city is null or ca.city LIKE :city) order by c.firstName").setParameter("name", name).setParameter("ref", customerRef).setParameter("city", city).getResultList();
below is my attempt :
Criteria orNameCriteria = new Criteria().orOperator(Criteria.where("firstName").is(null), Criteria.where("firstName").is(name), Criteria.where("lastName").is(name));
Criteria orCustomerRefCriteria = new Criteria().orOperator(Criteria.where("externalReference").is(null), Criteria.where("externalReference").regex(customerRef,"i"));
Criteria orAddress = new Criteria().orOperator(Criteria.where("addresses.city").is(null), Criteria.where("addresses.city").regex(city, "i"));
Query nameq = new Query(new Criteria().andOperator(orNameCriteria,orCustomerRefCriteria,orAddress));
this query return zero size arraylist. I've then changed the orNameCriteria to use is clause and making sure the data contained in name variable has / as suffix and prefix. That didn't work as well.
but queries from mongoVue and RockMongo clients :
{ firstName: /SAM/}
returns data.
Question 1: How do you write LIKE CLAUSE with spring-data-mongo Criteria?
Question 2 : is that the right way to use or and and clause with criteria
Thanks for reading
Criteria.where("field").regex(pattern) should work
Since I don't have the ability add comments...
If you do a static import on Criteria, it will make your where clauses look a lot better.
Criteria orAddress = new Criteria().orOperator(where("addresses.city").is(null), where("addresses.city").regex(city, "i"));
How can i do this from c# mongoDb drivers.
sql query :SELECT a,b FROM users
mondb javascript query : db.users.find({}, {a:1,b:1})
How about this:
var database = MongoDatabase.Create(connectionString);
var userCollection = database.GetCollection<Exercise>("users");
var users = userCollection.Find().SetFields("a", "b");
If I understand your question correctly .SetFields does what you want.
I am using MongoDb for my c sharp project instead of mysql, now i want to use query like select * from student Where (name is null or name='XXX') and (sno is null or sno=10), how can i build this query in mongodb.
thanks,
#dinnu.
This should get you started:
var mongoServer = MongoDB.Driver.MongoServer.Create("mongodb://localhost?safe=true");
var mongoDatabase = mongoServer.GetDatabase("test");
var mongoCollection = mongoDatabase.GetCollection<TModel>("Test");
var cursor = mongoCollection.Find(Query.And(
Query.Or(
Query.EQ("Name", "xxx"),
Query.EQ("Name", null)),
Query.Or(
Query.EQ("sno", 10)),
Query.EQ("sno", null)));
Where TModel is the type of the class you want to deserialize from the db. Now you can use cursor to iterate the results of that query, for example:
var someModel = cursor.FirstOrDefault();
Take a look at Fluent Mongo (https://github.com/craiggwilson/fluent-mongo). It adds Linq on top of the official 10gen driver. Thus far I have found using it to be a good experience. It is available via the Nuget or the GitHub.