C# MongoDB match any of elements in an array - c#

I have documents like this:
/* 1 */
{
"_id" : ObjectId("573f3944a75c951d4d6aa65e"),
"Source" : "IGN",
"Country" : "US"
}
/* 2 */
{
"_id" : ObjectId("573f3d41a75c951d4d6aa65f"),
"Source" : "VG",
"Country" : "Norway"
}
/* 3 */
{
"_id" : ObjectId("573f4367a75c951d4d6aa660"),
"Source" : "NRK",
"Country" : "Norway"
}
/* 4 */
{
"_id" : ObjectId("573f4571a75c951d4d6aa661"),
"Source" : "VG",
"Country" : "Norway"
}
/* 5 */
{
"_id" : ObjectId("573f468da75c951d4d6aa662"),
"Source" : "IGN",
"Country" : "US"
}
And a list of sources like this:
list = ['VG', 'IGN']
I want to return only the documents with source equals 'IGN' or 'VG' (any of elements in list)
How can I do this with the official C# mongodb driver?

Assuming you are using MongoDB C# driver version 2.2, you can use FilterDefinitionBuilder class to filter out desired results.
using System.Collections.Generic;
using System.Threading.Tasks;
using MongoDB.Bson;
using MongoDB.Driver;
... Your class and method declaration ...
IMongoClient client = new MongoClient ("mongodb://localhost:27017/test");
IMongoDatabase database = client.GetDatabase("test");
IMongoCollection<BsonDocument> collection = database.GetCollection<BsonDocument> ("collection");
var filter = Builders<BsonDocument>.Filter.AnyIn ("Source", new[]{"VG", "IGN"});
var cursor = await collection.FindAsync (filter);
var docs = cursor.ToList();
docs will hold only those documents with source either VG or IGN. Based on your sample data, it will have 4 documents.
I'll recommend you to have a look at how to Find or Query Data with C# Driver

It's a bit late, but I had the same question as OP and actually the accepted answer is wrong. AnyIn is the correct filter if your database object itself contains an array where you want to search.
In OP's (and also in my) case, the simple In filter is the correct one to use:
var filter = Builders<BsonDocument>.Filter.In("Source", new[]{"VG", "IGN"});
or with lambda
var filter = Builders<BsonDocument>.Filter.In(o => o.Source, new[]{"VG", "IGN"});

Related

translating mongo query to C# by using Filter

Is there any way to use Filters in C# and translate this mongo query?
{'EmailData.Attachments.Files': {$all: [{Name: 'a.txt'},{Name: 'b.txt'},{Name:'c.txt'}], $size: 3}}
my data model is like:
{
"_id": ObjectId("5f0a9c07b001406068c073c1"),
"EmailData" : [
{
"Attachments" : {
"Files" : [
{
"Name" : "a.txt"
},
{
"Name" : "b.txt"
},
{
"Name" : "c.txt"
}
]
}
}
]
}
I have something like this in my mind:
var Filter =
Builders<EmailEntity>.Filter.All(s => s.EmailData????);
or something like:
var Filter =
Builders<EmailEntity>.Filter.ElemMatch(s => s.EmailData???)
I was wondering is there any way in the above filter to use All inside ElemMatch?
The difficulty here is that EmailData.Attachments.Files is an array within another array so C# compiler will get lost when you try to use Expression Trees.
Thankfully there's another approach when you need to define a field using MongoDB .NET driver. You can take advantage of StringFieldDefinition<T> class.
Try:
var files = new[] { new FileData(){ Name = "a.txt"}, new FileData() { Name = "b.txt" }, new FileData() { Name = "c.txt" } };
FieldDefinition<EmailEntity> fieldDef = new StringFieldDefinition<EmailEntity>("EmailData.Attachments.Files");
var filter = Builders<EmailEntity>.Filter.And(
Builders<EmailEntity>.Filter.All(fieldDef, files),
Builders<EmailEntity>.Filter.Size(fieldDef, 3));
var result= collection.Find(filter).ToList();

Using MongoDB C# Driver write ElementMatch with Regex query

I need to construct the following query using MongoDB C# driver
db.Notes.find({ "Group._id" : 74, "CustomFields" : { "$elemMatch" : { "Value" : /batch/i } }, "IsDeleted" : false }).sort({ "CreatedDateTimeUtc" : -1 })
I used a query like this
builder.ElemMatch(x => x.CustomFields, x => x.Value.Contains(filterValue))
It generated mongo query as
db.Notes.find({ "Group._id" : 74, "CustomFields" : { "$elemMatch" : { "Value" : /batch/s } }, "IsDeleted" : false }).sort({ "CreatedDateTimeUtc" : -1 })
if you notice it is appending s at /batch/s instead of i /batch/i
How can I get this work? I need to do this for filters like
contains, using .Contains()
equals, thinking of using .Equals()
doesn't contain, thinking of using !Field.contains(value)
not equals to
starts with
ends with
Can I do something like this, so that I can apply all my regex patterns for all above filters.
builder.Regex(x => x.CustomFields[-1].Value, new BsonRegularExpression($"/{filterValue}/i"));
This converts the query to as below, but that doesn't get any results
db.Notes.find({ "Project._id" : 74, "CustomFields.$.Value" : /bat/i, "IsDeleted" : false }).sort({ "CreatedDateTimeUtc" : -1 })
FYI: builder is FilterDefinition<Note>
My sample Notes Collection is like this:
{
Name:"",
Email:"",
Tel:"",
Date:02 /21/1945,
CustomFields:[
{
Name:"",
Value:"",
IsSearchable:true,
},
{
Name:"",
Value:"",
IsSearchable:true,
},
{
Name:"",
Value:"",
IsSearchable:true,
},
{
Name:"",
Value:"",
IsSearchable:true,
}
]
}
It sounds like all you're missing is the insensitive part. Have you tried this?
ToLower, ToLowerInvariant, ToUpper, ToUpperInvariant (string method)
These methods are used to test whether a string field or property of
the document matches a value in a case-insensitive manner.
According to the 1.1 documentation here, it says that will allow to perform a case insensitive regex match.
The current documentation doesn't mention it, so just to be sure, i checked github and the code to create an insensitive match is still there.

How to find documents by ObjectId?

I have the following document in a mongodb collection
{
"_id" : "52bbd9bef2ba1f37f4f010c1",
"Name" : "Some Name",
"TypeId" : 1
}
I now want to edit this document using the c# driver
BsonDocument doc = BsonDocument.Parse(json);
IMongoQuery query = Query.And(Query.EQ("_id", doc["_id"]));
UpdateBuilder ub = MongoDB.Driver.Builders.Update.Set('Name', 'New Name');
WriteConcernResult updatedBook = _collection.Update(query, ub);
if (!updatedBook.UpdatedExisting)
{
// I always end here
}
It is also weird that the docs tell that _collection.Update(query, ub) should return a BsonDocument while they return a WriteConcernResult. Anyway if I use another property then _id I find the record.
It seems MongoDB is expecting a ObjectId() function wrapper around a ObjectId, isn't it? At least I need this in my tests while using MongoVUE.
Edit
If I try to find a record with this query
{
"_id" : "52bbd9bef2ba1f37f4f010c1"
}
I get nothing. If I use this
{
"_id" : ObjectId("52bbd9bef2ba1f37f4f010c1"),
}
it worked. So much for the Javascript way. AFAIK I have two ways to update a record with the native .net driver:
FindAndModifyResult
WriteConcernResult
But both ways expecting a BsonValue as value where ObjectId seems not to be a valid one...
So I tried using
IMongoQuery query = Query.And(Query.EQ("_id", doc["_id"]));
as described above but that is the same like
{
"_id" : "52bbd9bef2ba1f37f4f010c1"
}
So I wonder how to update a document by it's ObjectId?
When using the currently available Nuget published MongoDB driver for .NET, I can confirm that this code as an example works properly:
MongoClient client = new MongoClient(); // connect to localhost
MongoServer server = client.GetServer();
MongoDatabase test = server.GetDatabase("test");
MongoCollection examples = test.GetCollection("examples");
string id = "52bc958ca45026c2ff24f90b";
IMongoQuery query = Query.EQ("_id", ObjectId.Parse(id));
UpdateBuilder ub = Update.Set("Name", "George");
WriteConcernResult updatedBook = examples.Update(query, ub);
Using this collection data:
> db.examples.remove()
> db.examples.insert({Name:"Larry"})
> db.examples.find()
{ "_id" : ObjectId("52bc958ca45026c2ff24f90b"), "Name" : "Larry" }
Then, run the C# code above and check the collection again:
> db.examples.find()
{ "Name" : "George", "_id" : ObjectId("52bc958ca45026c2ff24f90b") }
While the WriteConcernResult class itself isn't a BsonDocument, the Response property contains the response from the command.
I also removed the unnecessary Query.And, as it's doesn't do anything when there's only one condition:
query = { "_id" : ObjectId("52bc958ca45026c2ff24f90b") }
ub = { "$set" : { "Name" : "George" } }

(mongodb) Fetching a bson object within a bson object using csharp

I have a collection which contains documents like:
{
field1: {subfield1:{ssfield1:5,ssfield2:6},subfield2:6},
field2: 1,
...
}
I'd like to fetch only the subfield, but I'm not sure how to get it querying from csharp (it doesn't seem to return the bsondocument within the bsondocument).
Any help?
I tried this:
String c = "mongodb://"+myip;
MongoServer server = MongoServer.Create(c);
MongoDatabase db = server.GetDatabase(mydb);
var collection = db.GetCollection(col);
string[] fields = new string[] { "field1" };
MongoCursor cursor = collection.Find().SetFields(fields);
but it seems to return
{subfield2:6}
I created a collection with one document very similar to your sample document:
> db.test.find().pretty()
{
"_id" : ObjectId("518ac1aa92f1c388279a9979"),
"field1" : {
"subfield1" : {
"ssfield1" : 5,
"ssfield2" : 6
},
"subfield2" : 6
},
"field2" : 1
}
>
Before showing the result I got when I attempted to reproduce your C# code, let's look at the same query in the MongoDB shell:
> db.test.find({}, { field1 : 1 }).pretty()
{
"_id" : ObjectId("518ac1aa92f1c388279a9979"),
"field1" : {
"subfield1" : {
"ssfield1" : 5,
"ssfield2" : 6
},
"subfield2" : 6
}
}
>
There are several things to notice here:
By default the server always returns the _id field
field1 was the only other field returned (just what we asked for)
subfield2 was returned because it's embedded in field1
I used slightly different C# code from yours to test:
foreach (var document in collection.FindAll().SetFields("field1"))
{
Console.WriteLine(document.ToJson(new JsonWriterSettings { Indent = true }));
}
And the output I got from that loop was:
{
"_id" : ObjectId("518ac1aa92f1c388279a9979"),
"field1" : {
"subfield1" : {
"ssfield1" : 5.0,
"ssfield2" : 6.0
},
"subfield2" : 6.0
}
}
which is essentially identical to the output from the MongoDB shell.
Let me know if you have any further questions.

Mongodb Array ElemMatch

I have a collection of documents:
"_id" : ObjectId("500d1aa9cf6640c15214fc30"),
"Title" : "Title0",
"Description" : "Description0",
"Keywords" : ["Keyword000", "Keyword001", "Keyword002", "Keyword003", "Keyword004", "Keyword005", "Keyword006", "Keyword007", "Keyword008", "Keyword009"],
"Category" : 0
I would like to query for items that have one keyword:
var query = Query.ElemMatch("Keywords", Query.EQ(XXX, "Keyword003"));
I have no idea on what to query on Query.EQ.
By turning the example into:
"_id" : ObjectId("500d4393cf6640c152152354"),
"Title" : "Title0",
"Description" : "Description0",
"Keywords" : [{
"Value" : "Keyword000"
}, {
"Value" : "Keyword001"
}],
"Category" : 0
And querying by
var query = Query.ElemMatch("Keywords", Query.EQ("Value", "Keyword001"));
I have no problem on getting the results.
Thank you.
The MongoDB query engine treats queries of the form { x : 123 } differently when x is an array. It matches any document where the x array contains 123. See:
http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-ValueinanArray
In your case, the query:
Query.EQ("Keywords", "Keyword003")
will match any document where the Keywords array contains "Keyword003". It might also contain other values, but that doesn't matter.
ElemMatch is only needed when the array is an array of embedded documents and you want to write a complex test against each of the embedded documents.
Have you tried quering keywords like the other keys in your document? The driver will returns the documents that contain the provided keyword
Bye

Categories

Resources