Retrieve Information BsonDocument - c#

Hi everybody in a previous post ( ListCollections with autorizedcollection ) I asked how to retrieve the name of the collections available in MongoDb'database. Finally the solution is much easier as expected and is :
var db = mongoUser.GetDatabase(databaseName);
var command = new CommandDocument { { "listCollections", 1 }, { "authorizedCollections", true }, {"nameOnly", true }};
var result = db.RunCommand<BsonDocument>(command);
the problem is I am not used to work with BsonDocument. I could cast the "result" into a BsonDocument or onto a string and then cut until I found the name of the solution. But it is the wrong way. Could someone help me for this case ?

you should not use CommandDocument since it's a Legacy API and you use not legacy code path in all other places. I think BsonDocument is the expected way to work with RunCommand. You can play with the above Deserialization suggestions but this will be just a step after RunCommand.
So I would expect something like this:
var command = new BsonDocument { { "listCollections", 1 }, { "authorizedCollections", true }, { "nameOnly", true } };
var result = db.RunCommand<BsonDocument>(command);
// any steps you want to process result including possible deserialization into typed view

Related

I have a JSON that I want to use in my Unity C# application where some properties are overloaded

Here's a simplified example. I want to pull in JSON data where the following are options:
{
"cost": 5
}
or
{
"cost": { "base": 5, "inc": 2}
}
Right now I'm using JsonUtility.FromJson<MyObject> which forces me to choose a single type. I am willing to convert one format to the other, so {"cost": 5} can become:
class MyObject
{
MyEntry cost = new MyEntry { #base = 5 };
}
Is there a way to do this using JsonUtility or another parser?
If you don't know or can't guarantee your object layout, then you'll have to use the dynamic mode.
var parsed = JObject.Parse(jsonString)
From here, you can call Value to try and get your data out.
var data = json.Value<string>("data")
// or
var data = json.Value<MyEntry>("data")
That should get you started.

MongoDB C# Driver how to update a collection of updated documents

I have a Mongo database with lots of documents. All of the documents have a field called "source" which contains the origin name for the document. But a lot of old documents have this field containing "null" (because I hadn't have source by that time) string value. I want to select all those documents and fix this problem by replacing their "source = "null"" values by new values parsed from another fields of the aforementioned documents.
Here's what I'm doing to fix the this:
public void FixAllSources() {
Task.Run(async ()=> {
var filter = Builders<BsonDocument>.Filter.And(new List<FilterDefinition<BsonDocument>>() {
Builders<BsonDocument>.Filter.Exists("url"),
Builders<BsonDocument>.Filter.Ne("url", BsonNull.Value),
Builders<BsonDocument>.Filter.Eq("source", "null")
});
var result = await m_NewsCollection.FindAsync(filter);
var list = result.ToList();
list.ForEach(bson => {
bson["source"] = Utils.ConvertUrlToSource(bson["url"].AsString);
});
});
}
as you can see, I'm fetching all those documents and replacing their source field by a new value. So now I've got a List of correct BsonDocuments which I need to put back into the database.
Unfortunately, I'm stuck on this. The problem is that all of the "Update" methods require filters and I have no idea what filters should I pass there. I just need to put back all those updated documents, and that's it.
I'd appreciate any help :)
p.s.
I've came up with an ugly solution like this:
list.ForEach(bson => {
bson["source"] = Utils.ConvertUrlToSource(bson["url"].AsString);
try {
m_NewsCollection.UpdateOne( new BsonDocument("unixtime", bson["unixtime"]), new BsonDocument {{"$set", bson}},
new UpdateOptions {IsUpsert = true});
}
catch (Exception e) {
WriteLine(e.StackTrace);
}
});
It works for now. But I'd still like to know the better one in case I need to do something like this again. So I'm not putting my own solution as an answer

How to pull ObjectId from an Array in a BsonDocument with C# MongoDriver 2.5

I'm trying to port over JavaScript code that interacts with a MongoDb to C# .NET and having problems with a delete/pull operation. I can't seem to figure out how to iterate over the Ponies array and remove a single ObjectId by matching to a passed in ObjectId.
{
"_id" : ObjectId("388e8a66fe2af4e35c60e"),
"Location" : "rainbowland",
"Ponies" : [
ObjectId("388e8a66fe2af4e35c24e83c"),
ObjectId("388e8a66fe2af4e35c24e860"),
ObjectId("388e8a66fe2af4e35c24e83d")
]
}
I've tried several different ways based on what I've found online but nothing seems to work. When I check the collection to see if 388e8a66fe2af4e35c24e860 was removed from the Ponies array I see that it wasn't removed. Everytime I execute the code and look at the ModifiedCount for resultPonies it shows zero. Two examples of what I've tried doing are below.
var pony = new Pony() { Id = new ObjectId("388e8a66fe2af4e35c24e860") }
var pullPonies = Builders<Ranch>.Update.PullFilter(x => x.Ponies,
y => y.Id == pony.Id);
var filterPonies = Builders<Ranch>.Filter.Where(x => true);
var resultPonies = _context.Ranches.UpdateMany(filterPonies, pullPonies);
OR
var pullPonies = Builders<BsonDocument>.Update.PullFilter("Ponies",
Builders<ObjectId>.Filter.Eq("ObjectId", pony.Id));
var filterPonies = Builders<BsonDocument>.Filter.Where(x => true);
var resultPonies = _context.Ranches.UpdateMany(filterPonies, pullPonies);
Here is the JavaScript code that I believe works but haven't been able to test yet.
db.collection("Ranches").update({}, {$pull: {Ponies: pony._id}}, {multi: true});
Ok, I found a solution for the problem. Since I'm not actually going to be filtering within the array of objects, they are all ObjectIds in a BsonArray, I need to find where the value in the array matches the given ObjectId. In those cases the array item should be pulled out. If the object in the array had other properties then I would probably want to use the PullFilter. But in this case I don't need to filter the additional level. That is at least what I believe I was doing wrong. Here are the solutions
var ponyId = new ObjectId("388e8a66fe2af4e35c24e860");
var pullPonies = Builders<Ranch>.Update.Pull(x => x.Ponies, ponyId);
// This line is to retrieve all Ranch objects in the collection
var filterPonies = Builders<Ranch>.Filter.Where(x => true);
var resultPonies = _context.Ranches.UpdateMany(filterPonies, pullPonies);
Or
var ponyId = new ObjectId("388e8a66fe2af4e35c24e860");
var pullPonies = Builders<BsonDocument>.Update.Pull("Ponies", ponyId));
// This line is to retrieve all Ranch objects in the collection
var filterPonies = Builders<BsonDocument>.Filter.Where(x => true);
var resultPonies = _context.Ranches.UpdateMany(filterPonies, pullPonies);

Parse & Unity 3D : Update an existing row

Using the example code from the Unity Developer Guide | Parse
# https://www.parse.com/docs/unity_guide#objects-updating
// Create the object.
var gameScore = new ParseObject("GameScore")
{
{ "score", 1337 },
{ "playerName", "Sean Plott" },
{ "cheatMode", false },
{ "skills", new List<string> { "pwnage", "flying" } },
};
gameScore.SaveAsync().ContinueWith(t =>
{
// Now let's update it with some new data. In this case, only cheatMode
// and score will get sent to the cloud. playerName hasn't changed.
gameScore["cheatMode"] = true;
It just adds a new row and leaves the original row unchanged.
I guess i'm thinking Parse would do something "SQL like" such as UPDATE where primaryKey = 123.
Searching for an answer i found this code #
https://parse.com/questions/updating-a-field-without-retrieving-the-object-first, but there was no example in C#. All attempts to port this to C# result in multiple syntax errors.
UnityScript:
// Create a pointer to an object of class Point with id dlkj83d
var Point = Parse.Object.extend("Point");
var point = new Point();
point.id = "dlkj83d";
// Set a new value on quantity
point.set("quantity", 6);
// Save
point.save(null, {
success: function(point) {
// Saved successfully.
},
error: function(point, error) {
// The save failed.
// error is a Parse.Error with an error code and description.
}
});
Does Parse have some way to update a row that already exists using C#? And where is it in the docs? And how can their own example be so useless?
One of the posts related to my question stated "retrieve the object, then write it back with the changes" and i had not the faintest idea how to execute the stated objective (especially after the epic fail of Parse Documentation's example code)
Here is what i have been able to figure out and make work:
var query = new ParseQuery<ParseObject>("Tokens")
.WhereEqualTo ("objectId", "XC18riofu9");
query.FindAsync().ContinueWith(t =>
{
var tokens = t.Result;
IEnumerator<ParseObject> enumerator = tokens.GetEnumerator();
enumerator.MoveNext();
var token = enumerator.Current;
token["power"] = 20;
return token.SaveAsync();
}).Unwrap().ContinueWith(t =>
{
// Everything is done!
//Debug.Log("Token has been updated!");
});
the first part retrieves the object with the stated objectId, the second part sets the fields in the object. The third part reports all is well with the operation.
it's a monkey see, monkey do understanding at this point being that i do not understand the finer points in the code.
the code can be tested by creating a class named "Tokens". in that class create a tokenName field and a power field. make a few rows with Fire, water, mud as the tokenNames. Replace the objectId in the .WhereEqualTo clause with a valid objectId or any other search parameters you like. Execute the code and observe the changes in the Parse Data Browser.
For extra credit create the class required to implement the example code from the Chaining Tasks Together section of Parse's Documentation.
https://www.parse.com/docs/unity_guide#tasks-chaining

Is this a proper use of dynamic keyword for returning JSON data

In my Controller, I have an action that returns JSON data as such:
[HttpGet]
public ActionResult AjaxJson(){
var ret = new List<dynamic>();
ret.Add(new{
Make = "Honda",
Year = 2011,
});
ret.Add(new{
Make = "BMW",
Fun = true
});
return Json(new { json = ret }, JsonRequestBehavior.AllowGet);
}
I'm a bit concern about the use of dynamic keyword because the items in the list is actually anonymous type. But there is noway to create a list of anonymous type.
My second question (not as important) is that if I return my JSON data as array. on the client, to get to Honda, I have to reference it this way: data.json[0].Make
But I want be able to do it this way: data.json.MyWeekdayCar.Make
I know that if I return JSON data as object (controller action listed later), I can reference Honda with data.json.MyWeekdayCar.Make, but I'll lose the ability to get its length with data.json.length. Is there a way to get the best of both world - able to use data.json.MyWeekdayCar.Make and count the number of objects on client side?
Controller to return JSON data as object:
[HttpGet]
public ActionResult AjaxJson(){
var ret = new{
MyWeekdayCar = new{
Make = "Honda",
Year = 2011
},
MyWeekendCar = new{
Make = "BMW",
Fun = true
},
length = 2 // this makes client side data.json.length work, but it doesn't feel normal.
};
return Json(new { json = ret }, JsonRequestBehavior.AllowGet);
}
EDIT
Are there side effects or unintended problems for using a list of dynamic with anonymous objects?
So to answer you first question there is not specifically anything wrong with using dynamic in the way that you are doing.
You will not be able to achieve exactly what you want without jumping through some hoops, but there are a couple of options available to you:
Option 1: You can write server side code looking something like this:
var honda = new { Make = "Honda", Year = "2011" };
var bmw = new { Make = "Bmw", Fun = true };
var array = new dynamic[] { honda, bmw };
var ret = new
{
Cars = array,
Length = array.Length,
MyWeekDayCar = honda,
MyWeekendCar = bmw
};
Then you can use this as follows in your javascript (not quite what you want but close):
data.json.MyWeekendCar.Make,
data.json.Cars.Length
data.json.Cars[0].Make
The downside to this approach is that you have to be very specific on the server side, and so it may be a bit inflexible. But it does involve the least work.
Option 2: Leave server side code as it is but without the length property:
var ret = new {
MyWeekdayCar = new{
Make = "Honda",
Year = 2011
},
MyWeekendCar = new{
Make = "BMW",
Fun = true
}
};
Then create class in javascript as a wrapper for your data that allows you to use it in the way you would want, for example:
CarsClass.prototype = Array.prototype; // Inherit from array type for length and other functions
function CarsClass(json) {
var that = this; // very important... but you'll need to research this yourself ;)
for (var key in json) // loop around all the properties in the object
{
if (json.hasOwnProperty(key))
{
that[key] = json[key]; // copy each property to our new object
that.push(json[key]); // add each property to our internal array
}
}
}
var cars = new CarsClass( // This is just dummy data, you would use your json
{
MyWeekdayCar : { Make: 'Honda', Year: '2011' },
MyWeekendCar : { Make: 'BMW', Fun: true },
AnotherCar: { Make: 'Skoda', FuelEfficient: true} // flexible!
});
alert(cars.MyWeekendCar.Make); // 'BMW'
alert(cars.length); // 3
alert(cars[0].Make); // 'Honda'
alert(cars[2].FuelEfficient); // True
You can see this working in this jsfiddle: http://jsfiddle.net/m49h5/
As you can see in this approach, you could add more cars on the server side and they would get picked up by the javascript class. Of course this approach would need to be more clever if you are then adding\removing cars on the client side. If you do need this then let me know and I can advise further
Hope this helps!
Is there a way to get the best of both world - able to use data.json.MyWeekdayCar.Make and count the number of objects on client side?
Not with anonymous types. You're creating a single object of an anonymous type with two properties: MyWeekdayCar and MyWeekendCar which are two different anonymous types.
So you don't have a collection of ojects, you have one object with two properties, all of which are different types. You'd have to add a length property when creating the objects.
What you could try is creating a Dictionary instead of a plain array:
var ret = new Dictionary<string,dynamic>();
ret.Add("MyWekedayCar",new{
Make = "Honda",
Year = 2011,
});
ret.Add("MyWeekendCar",new{
Make = "BMW",
Fun = true
});
Then I think you could access it as:
data.json.["MyWeekdayCar"].Make
data.json.length
Although to be honest I don't know enough about JSON/JavaScript and dictionaries to know if this works. If it doesn't I'll remove it from my answer.
If you want the best of both worlds, and your json format doesn't update regularly check out the JSON C# Class Generator: http://jsonclassgenerator.codeplex.com/
Every time you update your json format you can regenerate the classes for the frontend devs to use.
On the front end they can use the json.net libraries to deserialize your json into your generated classes as follows:
Car a = JsonConvert.DeserializeObject<Car> (json);
If this doesn't meet your requirements, the next best solution I'm aware of is to use the dynamic object as you suggested.

Categories