I have a JSON data (file attached). How can I parse it using C# using LitJSON? I am having trouble in deserialising it. Any help would be appreciated.
{
"vr-sessions" : {
"-KvDNAFD_BxlKEJ958eX" : {
"interview" : "Android",
"questions" : {
"-KvG7BuWu4eI52pq-6uH" : {
"playaudio" : "audio1",
"question" : "Why cannot you run standard Java bytecode on Android?"
},
"-KvG9rxQv5DWJa1EMnhi" : {
"playaudio" : "audio2",
"question" : "Where will you declare your activity so the system can access it?"
}
}
},
"-KvDNOE8YhVdgovxrzrN" : {
"interview" : "DevOps",
"questions" : {
"-KvMPd0v9BXnjYZxFm5Q" : {
"playaudio" : "audio3",
"question" : "Explain what is DevOps?"
},
"-KvMPi24OKeQTp8aJI0x" : {
"playaudio" : "audio4",
"question" : "What are the core operations of DevOps with application development and with infrastructure?"
},
"-KvMPqYxJunKp2ByLZKO" : {
"playaudio" : "audio5",
"question" : "Explain how “Infrastructure of code” is processed or executed in AWS?"
}
}
},
After adding a couple of missing braces and removing last comma, your json seems to be valid. However there's no way to declare a class or member starting with dash in C#. Not sure how LitJson would be able to map json values to a C# class if names don't match, unless you replace dashes before parsing the string with LitJson.
Workaround
In your Solution Explorer right click References and do Add Reference, then from Assemblies->Framework select System.Web.Extensions.
string jsonString = File.ReadAllText("json.txt");
dynamic json = new JavaScriptSerializer().Deserialize<dynamic>(jsonString);
Navigate to the value you're looking for
string interview = json["vr-sessions"]["-KvDNAFD_BxlKEJ958eX"]["interview"];
Variable interview gets value "Android" which is the same as doing this:
var sessions = json["vr-sessions"];
string interview = sessions["-KvDNAFD_BxlKEJ958eX"]["interview"];
If you don't know session names
Iterate to get question and playaudio values.
foreach (var session in json["vr-sessions"].Values)
{
foreach (var question in session["questions"].Values)
{
Console.WriteLine(question["question"]);
Console.WriteLine(question["playaudio"]);
}
}
Access to an element by position: let's say you want to iterate 0..N
var sessions = new List<dynamic>(json["vr-sessions"].Values);
Console.WriteLine(sessions[0]["interview"]);
This prints "Android" as the value of interview for session at position 0 is "Android".
Related
What should I use to create a list of big strings?List<string> myList=new List<string>();
myList.Add("very big string goes here");
Note that this way is giving an overflow error in csharp. What should I use instead of it?
Example string {
"_id" : ObjectId("59e625d5fdde4f78f8b3df28"),
"ID" : ObjectId("000000000000000000000000"),
"UserID" : "abcdef",
"BaseFileName" : "insert",
"FileID" : "insert.00001.txt.txt",
"FileData" : "��/F\u000f"
}
I have a document similar to the following document for storing licenses. Unnecessary fields are deleted.
{
"_id" : "1",
"company_name" : "stackOverflow",
"license_holders" : [
{
"UID" : "AAA-BBB-CCC-DDD",
"software_version" : "1.2.3",
"licenses" : [
{
"creation_date" : "03.03.17",
"is_valid" : true,
"license_id" : "l1"
},
{
"creation_date" : "03.03.16",
"is_valid" : false,
"license_id" : "l2"
}
]
},
{
"UID" : "111-222-333-444",
"software_version" : "1.2.3",
"licenses" : [
{
"creation_date" : "05.05.17",
"is_valid" : true,
"license_id" : "l3"
},
{
"creation_date" : "05.05.16",
"is_valid" : false,
"license_id" : "l4"
}
]
}
]
}
I can update a software version with a given UID by this query:
public async Task<Customer> UpdateLicenseHolderSoftwareVersion(string uid, string softwareVersion) {
var update = Builders<Customer>.Update.Set(c => c.LicenseHolders[-1].CurrentSoftwareVersion, softwareVersion);
Customer customer = await DMSLicenseCollection.FindOneAndUpdateAsync(c => c.LicenseHolders.Any(h => h.UID == uid), update);
return customer;
}
I couldn't find a way to update a license's "is_valid" field. I am trying to select the correct license with UID and LicenseId fields. I have tried many things but non of them succeeded. Is it a bad practice to embed this many documents? Or am i missing a way to update and retrieve a few layer nested documents which are inside arrays. Thanks...
I have couple of suggestions you could do to make your life easier.
I found it useful to not store nested documents as lists but dictionaries. That way you can easily find what subdocument you want to update. For example UID and license_id can be keys in your dictionary and values rest of fields.
I am not a big fan of identifying something in db that is not primary key. Here you update a subdocument based on UID and license_id. I think that is bad practice and would suggest you change that.
as for big documents that have lots of nested documents inside them you need to be moderate on how deep you go. More nested documents means slower query executions. I suggest you benchmark your app and check if you are satisfied with speed.
Solution for your current problem:
public async Task ToggleLicesneIsValid(string UID, int licenseId)
{
var filter = Builders<Customer>.Filter.ElemMatch(x => x.licence_holders, i => i.UID == UID);
var customer = DMSLicenseCollection.Find(filter).FirstOrDefault();
var item = customer.licence_holders.FirstOrDefault(x => x.UID == UID).licenses.FirstOrDefault(y => y.license_id == licenseId);
item.is_valid = !item.is_valid;
await DMSLicenseCollection.ReplaceOneAsync(o => o.mongoId == customer.mongoId, customer);
}
This method toggles true/false on "is_valid" but I suggest you have 2 separate methods (one for setting it true and one for setting it false). That way code is more readable and you can avoid potential bugs.
PS i named id mongoId in my tests but change it to your liking.
Cheers!
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
});
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"}})
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.