Mongodb Array ElemMatch - c#

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

Related

Mongodb Update or insert in c#

I want to update or insert into to mongo collection "Member". Under this collection i have an array MagazineSubscription. Here magazine Code is unique. Please refer the sample JSON.
So if need to update or insert into mongo using C# mongo driver.
First I need to check this code exist
2, If it exist update one
If it does not exist insert.
Is there any way I can do in one step. Like if it already exist update otherwise insert. Instead of hit twice. Because my collection is very big.
{
"_id" : ObjectId("5c44f7017en0893524d4e9b1"),
"Code" : "WH01",
"Name" : "Lara",
"LastName" : "John",
"DOB" : "12-10-2017",
"Gender" : "Male",
"Dependents" : [
{
"RelationShip" : "Son",
"Name" : "JOHN",
"DOB" : "01-01-1970",
"Gender" : "Male",
"Address" : "Paris",
"ContactNumber" : "+312233445666"
},
{
"RelationShip" : "Wife",
"Name" : "Marry",
"DOB" : "01-01-1980",
"Gender" : "Female",
"Address" : "Paris",
"ContactNumber" : "+312233445666"
}
]
"Matrimony" : [
{
"Fee" : 1000.0,
"FromDate" : "01-01-2015",
"ToDate" : "01-01-2017",
"Status" : false
}
],
"MagazineSubscription" : [
{
"MagazineCode" : "WSS",
"DateFrom" : "01-05-2018",
"DateTo" : "01-01-2020",
"PaidAmount" : 1000.0,
"ActualCost" : 1500.0,
"Status" : false,
"DeliveryStatus" : [
{
"ReturnedDate" : "10-01-2019",
"Comment" : "Returned because of invalid address"
},
{
"ReturnedDate" : "10-02-2019",
"Comment" : "Returned because of invalid address"
}
]
}
]
}
Use mongodb's update operation with upsert:true.
Please refer here: https://docs.mongodb.com/manual/reference/method/db.collection.update/
Here's a sample from the page:
db.collection.update(
<query>,
<update>,
{
upsert: <boolean>, //you need this option
multi: <boolean>,
writeConcern: <document>,
collation: <document>,
arrayFilters: [ <filterdocument1>, ... ]
}
)
And here's a similar question according to what you need:
Upserting in Mongo DB using official C# driver
EDIT 1
Steps:
First you need to write a filter to scan if the document exists. you can check any number of keys (Essentially a document).
Write the update section with the keys you'd like to update (Essentially a document).
Set upsert to true.
Mongodb will use your filter to search the document. If found, it will use the update section to perform the update mentioned by you.
In case the document does not exist, a new document will be created by using the filter keys + keys in the update part.
Hope that makes things clear as I have never used a C# mongo driver. So I won't be able to provide you the exact syntax.
EDIT 2
I'm providing #jeffsaracco's solution here:
MongoCollection collection = db.GetCollection("matches");
var query = new QueryDocument("recordId", recordId); //this is the filter
var update = Update.Set("FirstName", "John").Set("LastName","Doe"); //these are the keys to be updated
matchCollection.Update(query, update, UpdateFlags.Upsert, SafeMode.False);

How to Append to a Field in MongoDB C# [duplicate]

I have a document with a field containing a very long string. I need to concatenate another string to the end of the string already contained in the field.
The way I do it now is that, from Java, I fetch the document, extract the string in the field, append the string to the end and finally update the document with the new string.
The problem: The string contained in the field is very long, which means that it takes time and resources to retrieve and work with this string in Java. Furthermore, this is an operation that is done several times per second.
My question: Is there a way to concatenate a string to an existing field, without having to fetch (db.<doc>.find()) the contents of the field first? In reality all I want is (field.contents += new_string).
I already made this work using Javascript and eval, but as I found out, MongoDB locks the database when it executes javascript, which makes the overall application even slower.
Starting Mongo 4.2, db.collection.updateMany() can accept an aggregation pipeline, finally allowing the update of a field based on its current value:
// { a: "Hello" }
db.collection.updateMany(
{},
[{ $set: { a: { $concat: [ "$a", "World" ] } } }]
)
// { a: "HelloWorld" }
The first part {} is the match query, filtering which documents to update (in this case all documents).
The second part [{ $set: { a: { $concat: [ "$a", "World" ] } } }] is the update aggregation pipeline (note the squared brackets signifying the use of an aggregation pipeline). $set (alias of $addFields) is a new aggregation operator which in this case replaces the field's value (by concatenating a itself with the suffix "World"). Note how a is modified directly based on its own value ($a).
For example (it's append to the start, the same story ):
before
{ "_id" : ObjectId("56993251e843bb7e0447829d"), "name" : "London
City", "city" : "London" }
db.airports
.find( { $text: { $search: "City" } })
.forEach(
function(e, i){
e.name='Big ' + e.name;
db.airports.save(e);
}
)
after:
{ "_id" : ObjectId("56993251e843bb7e0447829d"), "name" : "Big London
City", "city" : "London" }
Old topic but i had the same problem.
Since mongo 2.4, you can use $concat from aggregation framework.
Example
Consider these documents :
{
"_id" : ObjectId("5941003d5e785b5c0b2ac78d"),
"title" : "cov"
}
{
"_id" : ObjectId("594109b45e785b5c0b2ac97d"),
"title" : "fefe"
}
Append fefe to title field :
db.getCollection('test_append_string').aggregate(
[
{ $project: { title: { $concat: [ "$title", "fefe"] } } }
]
)
The result of aggregation will be :
{
"_id" : ObjectId("5941003d5e785b5c0b2ac78d"),
"title" : "covfefe"
}
{
"_id" : ObjectId("594109b45e785b5c0b2ac97d"),
"title" : "fefefefe"
}
You can then save the results with a bulk, see this answer for that.
this is a sample of one document i have :
{
"_id" : 1,
"s" : 1,
"ser" : 2,
"p" : "9919871172",
"d" : ISODate("2018-05-30T05:00:38.057Z"),
"per" : "10"
}
to append a string to any feild you can run a forEach loop throught all documents and then update desired field:
db.getCollection('jafar').find({}).forEach(function(el){
db.getCollection('jafar').update(
{p:el.p},
{$set:{p:'98'+el.p}})
})
This would not be possible.
One optimization you can do is create batches of updates.
i.e. fetch 10K documents, append relevant strings to each of their keys,
and then save them as single batch.
Most mongodb drivers support batch operations.
db.getCollection('<collection>').update(
// query
{},
// update
{
$set: {<field>:this.<field>+"<new string>"}
},
// options
{
"multi" : true, // update only one document
"upsert" : false // insert a new document, if no existing document match the query
});

Find an specific element in a MongoDB document from C#

I am trying to access MongoDB from C# ASP.NET application.
Let's assume, I've a document like below-
{
"_id" : ObjectId("546c776b3e23f5f2ebdd3b03"),
"Name" : "Test",
"Values" : [
{
"Name" : "One",
"Value" : 1
},
{
"Name" : "Two",
"Value" : 2,
"Parameters": [{"Type": "Type A"}, {"Type": "Type B"}]
}
]
}
Please note that, only the _id and Name elements are fixed; other elements are dynamically created by the user where both the key and value are defined by the user.
Now, I would like to search for the element Type with the value Type A. How can I do this from a MongoDB C# driver?
You can use this code:
var query = Query.EQ("Values.Parameters.Type", "Type A");
var items = collection.Find(query).ToList();
If you data has structure use this:
var items = collection.FindAs<Item>(query).ToList();
Edit:
For dynaically search the only way comes to my mind is full-text-search:
Step1: Define a full text-search on all fields via db.test.ensureIndex({"$**" : "text"});
Step2: Search your query db.test.find( { $text: { $search: "Type A" } } )
If its your answer, the C# code should be easy.
Below aggregation query may solve your problem but I don't know how to write this in C#
db.collectioName.aggregate({"$unwind":"$Values"},
{"$unwind":"$Values.Parameters"},
{"$match":{"Values.Parameters.Type":"Type A"}},
{"$group":{"_id":"$Values"}})

Insert in to a nested array Using C# Official Driver MongoDB

Here is my exact schema:
{
"_id" : ObjectId("4fb4fd04b748611ca8da0d48"),
"Name" : "Categories",
"categories" : [{
"_id" : ObjectId("4fb4fd04b748611ca8da0d46"),
"name" : "Naming_Conventions",
"sub-categories" : [{
"_id" : ObjectId("4fb4fd04b748611ca8da0d47"),
"name" : "Namespace_Naming",
"standards" : []
}]
}]
}
As you can see I have an array named "standards" nested way down in there. How would I programmatically insert in to that using the C# driver? I have tried all of the examples I have found online but none of them are working.
Something like the below. Obviously, if any of these are not present on the way down to it, you're going to get a null reference exception.
var doc = collection.FindOne(Query.EQ("_id", new ObjectId("4fb4fd04b748611ca8da0d48")));
var standards = doc["categories"]
.AsBsonArray[0]
.AsBsonDocument["sub-categories"]
.AsBsonArray;
standards.Add(new BsonDocument());
collection.Save(doc);

Exact Contains Match on a Sub Collection

Using mongodb with the NoRM driver I have this document:
{
"_id" : ObjectId("0758030341b870c019591900"),
"TmsId" : "EP000015560091",
"RootId" : "1094362",
"ConnectorId" : "SH000015560000",
"SeasonId" : "7894681",
"SeriesId" : "184298",
"Titles" : [
{
"Size" : 120,
"Type" : "full",
"Lang" : "en",
"Description" : "House"
},
{
"Size" : 10,
"Type" : "red",
"Lang" : "en",
"Description" : "House M.D."
}
], yadda yadda yadda
and I am querying like:
var query = new Expando();
query["Titles.Description"] = Q.In(showNames);
var fuzzyMatches = db.GetCollection<Program>("program").Find(query).ToList();
where showNames is a string[] contain something like {"House", "Glee", "30 Rock"}
My results contain fuzzy matches. For example the term "House" returns every show with a Title with the word House in it ( like its doing a Contains ).
What I would like is straight matches. So if document.Titles contains "A big blue House" it does not return a match. Only if Titles.Description contains "House" would I like a match.
I haven't been able to reproduce the problem, perhaps because we're using different versions of MongoDB and/or NoRM. However, here are some steps that may help you to find the origin of the fuzzy results.
Turn on profiling, using the MongoDB shell:
> db.setProfilingLevel(2)
Run your code again.
Set the profiling level back to 0.
Review the queries that were executed:
> db.system.profile.find()
The profiling information should look something like this:
{
"ts" : "Wed Dec 08 2010 09:13:13 GMT+0100",
"info" : "query test.program ntoreturn:2147483647 reslen:175 nscanned:3 \nquery: { query: { Titles.Description: { $in: [ \"House\", \"Glee\", \"30 Rock\" ] } } } nreturned:1 bytes:159",
"millis" : 0
}
The actual query is in the info property and should be:
{ Titles.Description: { $in: [ "House", "Glee", "30 Rock" ] } }
If your query looks different, then the 'problem' is in the NoRM driver. For example, if NoRM translates your code to the following regex query, it will do a substring match:
{ Titles.Description: { $in: [ /House/, /Glee/, /30 Rock/ ] } }
I have used NoRM myself, but I haven't come across a setting to control this. Perhaps you're using a different version, that does come with such functionality.
If your query isn't different from what it should by, try running the query from the shell. If it still comes up with fuzzy results, then we're definitely using different versions of MongoDB ;)
in shell syntax:
db.mycollection.find( { "Titles.Description" : "House" } )

Categories

Resources