I have the following document:
{
"_id": {
"$oid": "55e1f841ff149c2228a5c33d"
},
"Status": "Open",
"Date": "8/30/2015",
"ContestName": "Test Contest",
"SearchableContestName": "test contest",
"ClassName": "Test",
"SearchableClassName": "test",
"Judges": [
{
"Name": "First Last",
"IsHeadJudge": null,
"_id": {
"$oid": "55e20962ff149c1f70d1aab0"
},
"ContestScores": null
},
{
"Name": "Another Name",
"IsHeadJudge": null,
"_id": {
"$oid": "55e20947ff149c1f70d1aaaf"
},
"ContestScores": [
1,
2,
3,
4,
5,
6
]
},
...
There are multiple judges in this list. I want to selectively update only the contest scores for the "First Last" name individual. I'm having difficulty figuring out the proper way to build my filters for this. I have:
public async void UpdateContestScores(ContestJudge judgeData, ObjectId contestId)
{
var contests = _db.GetCollection<BsonDocument>("contests");
var builder = Builders<BsonDocument>.Filter;
var updateFilter = builder.Eq("_id", contestId) & builder.Eq("Judges.Name", judgeData.Name);
var update = Builders<BsonDocument>.Update.Set("Judges.ContestScores", judgeData.ContestScores);
await contests.UpdateOneAsync(updateFilter, update);
}
This throws a bulk update error of some form. How do I go about updating this empty contest score field? I'm unsure of the proper filter syntax for such a thing.
Related
I want to remove a data in the my document. I bolded the id I want to remove
My Code like that but "This code deletes all KeyResultActions with same Id";
var filter = builder.Eq("Id", ObjectId.Parse(objectiveId))
& builder.Eq("KeyResults.Id", ObjectId.Parse(keyResultId))
& builder.Eq("KeyResults.KeyResultActions.Id", ObjectId.Parse(actionId));
var update = Builders<Objective>.Update.PullFilter("KeyResults.$[].KeyResultActions",
Builders<KeyResultAction>.Filter.Eq(x => x.Id, ObjectId.Parse(actionId)));
My document like that;
{
"_id": "**6311d1612559020ef536cb6f**",
"KeyResults": [
{
"_id": "6311d1612559020ef536cb69",
"Title": "Test KeyResult -1 ",
"Description": "Test KeyResult Desc -1",
"KeyResultActions": [
{
"_id": "630f5d4ebb4428127b11fb8e"
},
{
"_id": "630f5d4ebb4428127b11fb8f"
}
]
},
{
"_id": "**6311d1612559020ef536cb6b**",
"Title": "Test KeyResult -2",
"Description": "Test KeyResult Desc -2",
"KeyResultActions": [
{
"_id": "**630f5d4ebb4428127b11fb8e**"
},
{
"_id": "630f5d4ebb4428127b11fb8f"
}
]
}
]
}
You shouldn't use the $[] all positional operator which will remove the first item from the KeyResultActions array for all items in the KeyResults.
Instead, replace it with $ positional operator which selects the first matched element in the array.
MongoDB query
db.collection.update({
"_id": "6311d1612559020ef536cb6f",
"KeyResults._id": "6311d1612559020ef536cb6b",
"KeyResults.KeyResultActions._id": "630f5d4ebb4428127b11fb8e"
},
{
$pull: {
"KeyResults.$[].KeyResultActions": {
_id: "630f5d4ebb4428127b11fb8e"
}
}
})
MongoDB .NET Driver syntax
var update = Builders<Objective>.Update.PullFilter("KeyResults.$.KeyResultActions",
Builders<KeyResultAction>.Filter.Eq(x => x.Id, ObjectId.Parse(actionId)));
Demo
I'm using MongoDB 4.0 via the latest C# driver (v2.7.0 at this time). I have a document which has Options and Options have Inventory. So in other words, an array of inventory is nested within an array of options. How do I get down to the inventory level and update the inventory only?
Here's what my document looks like in JSON form:
{
"Options": [
{
"Id": 1,
"Description": "This is one option",
"Inventory": [
{
"Id": 1,
"Name": "Box of stuff"
},
{
"Id": 2,
"Name": "Another box of stuff"
}
]
},
{
"Id": 2,
"Description": "This a second option",
"Inventory": [
{
"Id": 1,
"Name": "Box of stuff"
},
{
"Id": 2,
"Name": "Another box of stuff"
}
]
}
]
}
Using the C# driver, how do I change the name of a single inventory item within a single option, if I know the Id of the option and the Id of the inventory item?
In MongoDB 4.0 you can use the $[<identifier>] syntax and add ArrayFilters to UpdateOptions parameter:
var filter = Builders<Model>.Filter.Empty;
var update = Builders<Model>.Update.Set("Options.$[option].Inventory.$[inventory].Name", "New name");
var arrayFilters = new List<ArrayFilterDefinition>();
ArrayFilterDefinition<BsonDocument> optionsFilter = new BsonDocument("option.Id", new BsonDocument("$eq", optionId));
ArrayFilterDefinition<BsonDocument> inventoryFilter = new BsonDocument("inventory.Id", new BsonDocument("$eq", inventoryId));
arrayFilters.Add(optionsFilter);
arrayFilters.Add(inventoryFilter);
var updateOptions = new UpdateOptions { ArrayFilters = arrayFilters };
var result = DefaultCollection.UpdateOne(filter, update, updateOptions);
That will uniquely identify Inventory item that needs to be updated inside Options
I am new in MongoDB and I am developing a software by C# and MongoDB. My data structure is like this
{
"Id": 1,
"Title": "myTitle",
"Geners": [ "Drama", "Action" ],
"Category": 1,
"Casts": [
{
"Id": 1,
"Name": "myName",
"Gender": "Male",
"Age": 35
},
{
"Id": 2,
"Name": "herName",
"Gender": "Female",
"Age": 30
},
{
"Id": 3,
"Name": "hisName",
"Gender": "Male",
"Age": 45
}
]
}
This is just one document and I have about 5 million documents. I want to run a query like below to count the records based on Category and shows me how many movie do I have in each category and I want to put Casts field in result.
db.getCollection('myCollection').aggregate([
{
$group:{"_id":"$Category", "count": {$sum:1},
"Casts":{$push:"$Casts"}}
}
])
this is close to something I want but the problem is, it puts Casts data in second level of array like {"Id":1, ... , "Casts":[[{},{},...]]} but I need it like this {"Id":1, ... , "Casts":[{},{},...]}
How can I show the data like that?
If duplicates are acceptable, then the following aggregation will suffice:
db.getCollection('myCollection').aggregate([
{ $unwind:"$Casts"},
{
$group:{"_id":"$Category", "count": {$sum:1},
"Casts":{$push:"$Casts"}}
}
])
Update:
Since you need the count to be valid, there's a few more hoops to jump through.
db.getCollection('myCollection').aggregate([
{ $group:{"_id":"$Category", "count": {$sum:1}, "Casts":{$addToSet:"$Casts"}}},
{$unwind:"$Casts"},
{$unwind:"$Casts"},
{ $group:{"_id":"$_id", "count": {$first:"$count"}, "Casts":{$addToSet:"$Casts"}}},
])
Let me know if that helps
I am using data from a Json object to populate a list view. The object has these parameters:
"id": "339150749455906",
"posts": {
"data": [
{
"id": "339150749455906_545370565500589",
"from": {
"category": "Food/beverages",
"name": "Pepsi",
"id": "339150749455906"
},
"story": "Pepsi updated their cover photo.",
"picture": "http://photos-g.ak.fbcdn.net/hphotos-ak-ash3/942740_545370555500590_46289134_s.jpg",
"link": "http://www.facebook.com/photo.php?fbid=545370555500590&set=a.365573920146922.72816.339150749455906&type=1&relevant_count=1",
"icon": "http://static.ak.fbcdn.net/rsrc.php/v2/yz/r/StEh3RhPvjk.gif",
"actions": [
{
"name": "Comment",
"link": "http://www.facebook.com/339150749455906/posts/545370565500589"
},
{
"name": "Like",
"link": "http://www.facebook.com/339150749455906/posts/545370565500589"
}
],
I want to access the link inside the parameter/key "actions". So far I am using:
foreach (var post in postsTaskResult.posts.data)
{
link = new Uri(string.Format("{0}", (string)post["link"]));
}
However, this only brings the link in the "data". How can I access the other 'link' ?
Try this.
var actionLinks = new List<string>();
var actions = post["actions"] as JArray; // if this works then all is well
foreach(var item in actions)
{
actionLinks.Add((string)item["link"]);
}
I think you can also use some fancy Linq with this like
var actionLinks = ((JArray)post["actions"])
.Children<JObject>()
.Select(a => (string)a["link"])
.ToList();
Very un-tested. Just let me know.
I've spent MANY hours looking for the answer...
This is very easy in PHP but I just can't put it together in C#(I'm new to C# and mongo...)
I'm trying to iterate through all levels of a stored document. The document looks like this:
{
"_id": ObjectId("51f90101853bd88971ecdf27"),
"fields": [
{
"ID": ObjectId("51fd09498b080ee40c00514e"),
"NAME": "ID",
"TYPE": "Text"
},
{
"ID": ObjectId("51fd09a68b080ee40c0064db"),
"NAME": "Title",
"TYPE": "Text"
},
{
"ID": ObjectId("51fd09b28b080ee40c004d31"),
"NAME": "Start Date",
"TYPE": "Date"
},
{
"ID": ObjectId("51fd09c28b080ee40c007f2e"),
"NAME": "Long Description",
"TYPE": "Memo"
}
],
"name": "TODB",
"updated": "Wed Jul 31 2013 08:20:17 GMT-0400 (Eastern Daylight Time)"
}
I have no problem accessing the "name" and "updated" but can't figure out how to access the "fields" array.
Code so far :
{
MongoServer mongo = MongoServer.Create();
mongo.Connect();
var db = mongo.GetDatabase("forms");
mongo.RequestStart(db);
var collection = db.GetCollection("forms");
var query = new QueryDocument("name",
"TODB");
mongo.Disconnect();
}
#foreach(BsonDocument item in collection.Find(query))
{
#item.GetElement("name").Value
#item.GetElement("_id").Value
}
Again, I am able to access the name and _id just not any of the sub document values.
Thanks in advance for any assistance!
After I get the reading figured out, I am also going to want to write data....
There are a few ways, but here's one:
// build some test data
BsonArray dataFields = new BsonArray { new BsonDocument {
{ "ID" , ObjectId.GenerateNewId()}, { "NAME", "ID"}, {"TYPE", "Text"} } };
BsonDocument nested = new BsonDocument {
{ "name", "John Doe" },
{ "fields", dataFields },
{ "address", new BsonDocument {
{ "street", "123 Main St." },
{ "city", "Madison" },
{ "state", "WI" },
{ "zip", 53711}
}
}
};
// grab the address from the document,
// subdocs as a BsonDocument
var address = nested["address"].AsBsonDocument;
Console.WriteLine(address["city"].AsString);
// or, jump straight to the value ...
Console.WriteLine(nested["address"]["city"].AsString);
// loop through the fields array
var allFields = nested["fields"].AsBsonArray ;
foreach (var fields in allFields)
{
// grab a few of the fields:
Console.WriteLine("Name: {0}, Type: {1}",
fields["NAME"].AsString, fields["TYPE"].AsString);
}
You can often use the string indexer ["name-of-property"] to walk through the fields and sub document fields. Then, using the AsXYZ properties to cast the field value to a particular type as shown above.