I use C# MongoDb Driver and I try to build Aggregation with Fluent aggregation pipelines.
In some stage in my aggregation I use MATCH that has to find documents if some field in document equals to another.
For example, I have this documents:
[
{
"Product" : "PROD1",
"SubField" : "2",
"ShortDescription" : "string",
"LongDescription" : "string",
"SubFields" : {
"Field" : "1"
}
},
{
"Product" : "PROD2",
"SubField" : "3",
"ShortDescription" : "string",
"LongDescription" : "string",
"SubFields" : {
"Field" : "3"
}
}
]
In Studio 3T this MATCH stage code works OK:
{
$expr: {$eq: ["$SubField", "$SubFields.Field"]}
}
I tried in C# this code, but it does not work:
.Match( x => x["SubField"] == x["SubFields.Field"])
I would appreciate help,
TIA,
Yaakov.
.net driver allows passing raw mql instead typed. So try this:
.Match("{ $expr: {$eq: ["$SubField", "$SubFields.Field"] } }")
Related
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);
Given a document structure:
[{
_id: ObjectId("someId"),
Property: {
CollectionProperty: [{
ItemKey: 28,
StringArray: [
"ItemA",
"ItemB"
]
}]
}
}]
Performing the following operation in the mongo shell does what I want:
db.getCollection('collection').updateOne(
{
"_id" : ObjectId("someId"),
"Property.CollectionProperty.ItemKey" : 28
},
{ $push :
{
"Property.CollectionProperty.$.StringArray" : {
$each : [ "AItemA" ],
$sort : 1
}
}
});
However, I cannot find in the documentation or anywhere on the net how to reproduce THAT $sort command in C# code. I can reproduce if it had fields by using "field":1, but not a non-document array like that.
The mongodb documentation that describes that sort is here:
MongoDB Sort Elements that are not documents
Here's what I have in C# so far:
Builders<DataType>.Update.PushEach("Property.CollectionProperty.$.StringArray",
new[] { "AItemA" }, null, null, ???)));
The ??? is what I don't know how to do... does anyone have any suggestions?
TIA
This is apparently currently unsupported, but planned for a future release in the C# driver, as documented here:
https://jira.mongodb.org/browse/CSHARP-1271
I have this following query working on mongo shell as expected.
db.getCollection('personnels').update(
{
_id: ObjectId("55f6728b9d73a15807885de8"),
"Devices._id":ObjectId("55fa5f7ac9e7863a3836e331")
},
{
$pull:{ "Devices.$.DeviceCloudFolders": { "CloudFolderId": ObjectId("5615124b06275f072040c4f1")}}
}
);
And here is my document structure:
{
"_id" : ObjectId("55f6728b9d73a15807885de8"),
"FirstName" : "Tolga",
"Devices" : [
{
"_id" : ObjectId("55fa5f7ac9e7863a3836e331"),
"Name" : "tolga-laptop",
"DeviceCloudFolders" : [{
"AuthorityType" : 1,
"CloudFolderId" : ObjectId("55f96db5c9e7863a3836e310"),
"Status" : 1
}],
"Status" : 1
}
],
"Status" : 1
}
I need to use it in C# and couldn't figure out how.
I started with these lines:
var filter = Builders<Personnel>.Filter.And(
Builders<Personnel>.Filter.Eq("_id", ownerPersonnelId),
Builders<Personnel>.Filter.Eq("Devices._id", _id));
var update = Builders<Personnel>.Update.PullFilter("Devices.$.DeviceCloudFolders", /*couldn't figure out what goes here*/))
Personnels.FindOneAndUpdateAsync(filter, update);
I'm not sure, but you can try using this:
var update = Builders<Personnel>.Update.PullFilter(
"Devices.$.DeviceCloudFolders",
Builders<DeviceCloudFolder>.Filter.Eq("CloudFolderId", _cloudFolderId));
I'm using version 1.5.0.4566 of the official MongoDB C# driver. I'm using Mongo version 2.06.
Here is what my document structure looks like (omitted fields not necessary for this discussion):
{ "Parents" :
[
{
"CreatedOn": ISODate("2012-07-28T15:30:06.623Z"),
"Title": "Simple Title",
"Children": [
{ "StatusId": 1, "Active" : true, SubChild : { "ExpiresOn": ISODate("2012-07-28T15:30:06.623Z")}},
{ "StatusId": 1, "Active" : true, SubChild : { "ExpiresOn": ISODate("2012-08-28T15:30:06.623Z")}}
]
},
{
"CreatedOn": ISODate("2012-07-28T15:30:06.623Z"),
"Title": "Another Simple Title",
"Children": [
{ "StatusId": 1, "Active" : true, SubChild : { "ExpiresOn": ISODate("2012-07-28T15:30:06.623Z")}},
{ "StatusId": 1, "Active" : true, SubChild : { "ExpiresOn": ISODate("2012-08-28T15:30:06.623Z")}}
]
}
]
}
If I wanted to query the Children that have a StatusId equal to one and Active is true I can use ElemMatch.
Query.ElemMatch("Children", Query.And(Query.EQ("StatusId", 1),Query.EQ("Active",true)));
What I cannot get to work is when I need to include the SubChild element in my query.
Query.ElemMatch("Children", Query.And(Query.EQ("StatusId",1), Query.EQ("Active",true),Query.LT("SubChild.ExpiresOn",DateTime.UtcNow)));
The query doesn't return any values when I try to include the SubChild.ExpiresOn field in the query. I have tried different ways to build this query, but keep getting zero documents when I include the SubChild.ExpiredOn field.
What am I missing?
Thanks,
Try this instead
Query.ElemMatch("Children", Query.And(Query.EQ("StatusId",1), Query.EQ("Active",true),Query.LT("SubChild.ExpiresOn",DateTime.UtcNow)));
Wondering why this query magically works? It's the case (StatusId vs StatusID). JavaScript is case sensitive.
You could eliminate this problem by using strongly typed Linq queries, like:
from x in collection.AsQueryable()
where x.Children.Any(child =>
child.StatusId == 1
&& child.Active
&& child.SubChild.ExpiresOn < DateTime.UtcNow)
select x
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" } )