imagine this structure:
collection companies:
{
"company" : "foo",
"city" : "1234"
}
{
"company" : "bar",
"city" : "1234"
}
collection cities:
{
"_id" : "1234",
"cityname" : "Berlin",
"zipcode" : "09123"
}
now i want to get as result when i query for company = "foo":
{
"company" : "foo",
"city" : {
"_id" : "1234",
"cityname" : "Berlin",
"zipcode" : "09123"
}
}
How to query this from the C# driver? i have the result structure as C# class and i would like to have it strong-typed.
like this:
MongoCollection<Company> mc = mongodb.GetCollection<Company>("companies")
And the Class company looks like:
public class Company {
public string company {get;set;}
public City city {get;set;}
}
You should get the idea.
The Mongo ducomentation didn't say much about this.
Your are frequently asking the city data by reference, embedding this document makes it faster to query.
Restructure your document schema and embed the city (address) document into the company document.
{
company : "Deutsche Bank",
address : {
street : "Müllerstraße",
number : "34a",
zipcode : "13353",
city : "Berlin"
}
}
If you have no other option because of any business logic is relying on the company document, you could choose to create aggregation queries and project a new document as result.
[additional info]
You have to run an extra query to get the referenced document, foreach every company and embed the city info.
Related
So, I have a json file in the following format
{
"-KeArK3V02mXYWx2OMWh" : {
"Description" : "this is a description",
"Location" : "Atlanta",
"Name" : "Event One",
"Time" : "2017-03-01T21:53:12.924645Z"
},
"-KeAtCNF_rmewZ_U3PpH" : {
"Description" : "another description",
"Location" : "Charlotte",
"Name" : "Event Two",
"Time" : "2017-03-01T22:01:25.603547Z"
},
"-KeAtd8CQW_EfH3Sw4YQ" : {
"Description" : "description goes here",
"Location" : "Toronto",
"Name" : "Event Three",
"Time" : "2017-03-01T22:03:19.3953859Z"
}
}
and I have a class called Event that is defined as follows
class Event {
public string Description { get; set; }
public string Location { get; set; }
public string Name { get; set; }
public DateTime Time { get; set; }
}
and I'd like to go through this and deserialize each of the child nodes into Event objects, basically deserializing the entire JSON into a List<Event>.
The issue is that the events aren't in an array, they're child nodes of another JSON object. So it turns out it's not as simple as
List<Event> elist = JsonConvert.DeserializeObject<List<Event>>(jsonResult);
I've seen similar questions asked where the items were organized in a JSON array, and I've tried the solutions listed there but they only work when it's an actual array, not the structure I have here. Google Firebase is what I'm working with here and unfortunately it doesn't support JSON arrays, so I have no way of containing the items in an array instead.
I'm not really used to JSON syntax so I might be missing something really obvious here, but I'm completely stumped.
Any help would be greatly appreciated.
Can you try this approach? It's pretty straight forward
var str = #"{
'-KeArK3V02mXYWx2OMWh' : {
'Description' : 'this is a description',
'Location' : 'Atlanta',
'Name' : 'Event One',
'Time' : '2017-03-01T21:53:12.924645Z'
},
'-KeAtCNF_rmewZ_U3PpH' : {
'Description' : 'another description',
'Location' : 'Charlotte',
'Name' : 'Event Two',
'Time' : '2017-03-01T22:01:25.603547Z'
},
'-KeAtd8CQW_EfH3Sw4YQ' : {
'Description' : 'description goes here',
'Location' : 'Toronto',
'Name' : 'Event Three',
'Time' : '2017-03-01T22:03:19.3953859Z'
}
}";
Dictionary<string, Event> elist = JsonConvert.DeserializeObject<Dictionary<string, Event>>(str);
How to do aggregation query with Linq. I know there is a AsQueryable() interface. But it seems throwing errors when I do aggregations.
If I have a collection called person stores data like this:
{
"Name": "Punny",
"Interests": [
1,
2
]
}
and another collection called interests stores data like this:
{
"_id":1,
"name":"music"
},
{
"_id":2,
"name":"read"
}
I want to get something like this:
{
"Name": "Punny",
"Interests": [
"music",
"read"
]
}
How can I achieve this via Linq to with AsQueryable?
I tried this:
_context.People.AsQueryable()
.Select(p => new
{
Name = p.Name,
Interests = p.InterestingIds
.Join(_context.Interests.AsQueryable(),
per => per,
i => i.Id,
(per, i) => new {i.Name})
}).ToList();
It throws a System.NotSupportedException
System.NotSupportedException : Join of type System.Linq.Enumerable is not supported in the expression tree {document}{InterestingIds}.Join([FunnyMongoBlog.interest], per => per, i => i.Id, (per, i) => new <>f__AnonymousType1`1(Name = i.Name)).
I tried my self with a two trip to database:
var person = _context.People.AsQueryable()
.Single(p => p.Name == "Punny");
var ids = person.InterestingIds;
var query = _context.Interests.AsQueryable()
.Where(i => ids.Contains(i.Id)).ToList();
var result = new
{
person.Name,
Interest = query
};
This is working but I wonder if we can do it with one trip so that the database could handle the aggregation.
you can do it in aggregation framework, but I'd to suggest using power of subDocumnets in mongoDB and embed those elements fully in main document. In other words we need to switch from relational thinking to document thinking.
My suggested object shape:
{
"Name" : "Punny",
"Interests" : [{
"_id" : 1,
"name" : "music"
}, {
"_id" : 2,
"name" : "read"
}
]
}
in c# code
class MyClass {
public string Name;
public List < Interest > Interests;
}
class Interest {
public int Id;
public string Name;
}
Now please find bson document needed for that transformation requested in question:
db.col.aggregate([{
$unwind : "$Interests"
}, {
$lookup : {
from : "interests",
localField : "Interests",
foreignField : "_id",
as : "interest"
}
}, {
// now we need to reshape document
$project : {
_id : 1,
Name : 1,
Interests : "$interest.name"
}
},
//group documents back
{
$group : {
_id : {
id : "$_id",
name : "$Name"
},
Interests : {
$push : "$Interests"
}
}
}, {
//final reshape
_id : "$_id.id",
Name : "$_id.name",
Interests : 1
}
])
and decide if embeding is worth a try :-)
Any comments welcome!
I have a collection as "UserRecords". structure for this is as follows
{
"_id" : "ee654ce6-e50d-4243-8738-35c087a85e67",
"_t" : "Animals",
"ClickedOn" : NumberLong(1452600122),
"Category" : "Nature",
"UserId" : "a1",
}
{
"_id" : "ee654ce6-e50d-4243-8738-35c087a85e67",
"_t" : "Abstract",
"ClickedOn" : NumberLong(1247634566),
"Category" : "Modern",
"UserId" : "a1",
}
{
"_id" : "ee654ce6-e50d-4243-8738-35c087a85e67",
"_t" : "Abstract",
"ClickedOn" : NumberLong(1247634440),
"Category" : "Modern",
"UserId" : "a1",
}
and more...
now I want to get Max clicked on for each category. Using latest Mongo C# driver
something like
select Max(clicked) from table group by Category in SQL.
Queries like this can be efficiently processed with the MongoDB Aggregation Framework. However, the queries are written as JSON, making them a bit hard to read.
var dataCollection = Database.GetCollection("UserRecords");
var AggArgs = new AggregateArgs {
Pipeline =
new[] {BsonDocument.Parse(#"{$group : {_id : '$Category', ClickedOn : {$max : '$ClickedOn'}}}")}
};
foreach (var result in dataCollection.Aggregate(AggArgs))
{
Console.WriteLine($"Category: {result["_id"]} Clicked: {result["ClickedOn"]}");
}
What I have is a MongoDB which contains a collection of products. Lets say each product has the following structure:
public ObjectId Id { get; set; }
public string label { get; set; }
public List<IngredientsModel> ingredients { get; set; }
Now my C# program gets notified via the oplog if there was a change. This oplog looks like this:
{
"ts" : Timestamp(1425392023, 1),
"h" : NumberLong("-7452324865462273810"),
"v" : 2,
"op" : "u",
"ns" : "coll.products",
"o2" : { "_id" : ObjectId("54f5b87cd4c6959bd3ecf2d6") },
"o" : { "$set" : { "ingredients.1.ingredid" : "54f5c117d4c6959bd3ecf2e8" } }
}
When my application starts I create a list of products which I get from the MongoDB. I just use products.findAll() and the put them in a List<'products>
I have several clients connected to the MongoDB and every client gets notified via oplog.
Now I want to update my local lists without querying the MongoDB since I have all the information needed to update my local products already in the oplog.
My question is now: How to do that?
My approach is the following:
Deserialize the object to Json
var prodjson= Product[0].ToJson<ProductModel>();
Convert Json to BsonDocument
var prodbson= BsonSerializer.Deserialize<BsonDocument>(prodjson);
Apply the "o" key from the oplog to the prodbson
"o" : { "$set" : { "ingredients.1.ingredid" : "54f5c117d4c6959bd3ecf2e8" } }
NO IDEA
From an API I receive a JSON-object that looks like this:
{
"wind" : {
"speed" : 7.31,
"deg" : 187.002
},
"rain" : {
"3h" : 0
},
"clouds" : {
"all" : 92
},
"coord" : {
"lon" : 139,
"lat" : 35
},
"dt" : 1369824698,
"id" : 1851632,
"cod" : 200,
"weather" : [
{
"id" : 804,
"main" : "clouds",
"icon" : "04n",
"description" : "overcast clouds"
}
],
"main" : {
"humidity" : 89,
"temp_max" : 292.04,
"temp_min" : 287.04,
"temp" : 289.5,
"pressure" : 1013
},
"sys" : {
"country" : "JP",
"sunrise" : 1369769524,
"sunset" : 1369821049
},
"name" : "Shuzenji"
}
I would like to assign two of these values to my class:
public class Weather {
public string Name { get; set; }
public string Temp { get; set; }
}
The name I can assign like this:
weather.Name = TheJSON.name.ToString();
But the temp is trickier, because it's nested inside the "main"-array. I´ve seen many examples on how to do this in Javascript but not so much in C#. Thanks!
Main is not an array. It is an object, so
TheJSON.main.temp.ToString()
The easiest way to work with JSON data is to deserialize them as C# objects and directly use them in your application. You can use a tool like JSON C# Class Generator to automatically generate the C# class from the JSON data. Once you have your C# classes generated, you can deserialize the JSON string using the JsonConvert.DeserializeObject(jsonText); The generated code requires Newtonsoft Json.NET which you can easily add as a NuGet package.
If you save your JSON content in D:\test.json, you can use the following code to access the values using the C# objects generated. The example below is to just give you an idea on the usage.
var json = File.ReadAllText(#"D:\test.json");
var weather = JsonConvert.DeserializeObject<Weather>(json);
Console.WriteLine(weather.Name);
Console.WriteLine(weather.Sys.Country);