Retrieving list of documents from collection by id in nested list - c#

I have documents like this:
[
// 1
{
"_id": ObjectId("573f3944a75c951d4d6aa65e"),
"Source": "IGN",
"Family": [
{
"Countries": [
{
"uid": 17,
"name": "Japan",
}
]
}
]
},
// 2
{
"_id": ObjectId("573f3d41a75c951d4d6aa65f"),
"Source": "VG",
"Family": [
{
"Countries": [
{
"uid": 17,
"name": "USA"
}
]
}
]
},
// 3
{
"_id": ObjectId("573f4367a75c951d4d6aa660"),
"Source": "NRK",
"Family": [
{
"Countries": [
{
"uid": 17,
"name": "Germany"
}
]
}
]
},
// 4
{
"_id": ObjectId("573f4571a75c951d4d6aa661"),
"Source": "VG",
"Family": [
{
"Countries": [
{
"uid": 10,
"name": "France"
}
]
}
]
},
// 5
{
"_id": ObjectId("573f468da75c951d4d6aa662"),
"Source": "IGN",
"Family": [
{
"Countries": [
{
"uid": 14,
"name": "England"
}
]
}
]
}
]
I want to return only the documents with source equals 'Countries.uid' equal 17
so I have in the end :
[
{
"_id": ObjectId("573f3944a75c951d4d6aa65e"),
"Source": "IGN",
"Family": [
{
"Countries": [
{
"uid": 17,
"name": "Japan",
}
]
}
]
},
{
"_id": ObjectId("573f3d41a75c951d4d6aa65f"),
"Source": "VG",
"Family": [
{
"Countries": [
{
"uid": 17,
"name": "USA"
}
]
}
]
},
{
"_id": ObjectId("573f4367a75c951d4d6aa660"),
"Source": "NRK",
"Family": [
{
"Countries": [
{
"uid": 17,
"name": "Germany"
}
]
}
]
}
]
How can I do this with the official C# MongoDB driver?
Tried this :
public List<Example> getLinkedCountry(string porduitId)
{
var filter = Builders<Example>.Filter.AnyIn("Family.Countries.uid", porduitId);
var cursor = await _certificats.FindAsync(filter);
var docs = cursor.ToList();
return docs;
}
Unfortunately, I think my filter is wrong.
Is there a way to find all the documents by accessing the nested list by id and retrieving it?

Solution 1
Use ElemMatch instead of AnyIn.
var filter = Builders<Example>.Filter.ElemMatch(
x => x.Family,
y => y.Countries.Any(z => z.uid == porduitId));
Output
Solution 2
If you are unconfident with MongoDB .Net Driver syntax, you can convert the query as BsonDocument via MongoDB Compass (Export to language feature).
var filter = new BsonDocument("Family.Countries.uid", porduitId);

Just to expand on #Yong Shun 's answer,
if you just want to return the list of nested documents and not all of it, you have a few options.
Using project
var filter = Builders<Example>.Filter.ElemMatch(
x => x.Family,
y => y.Countries.Any(z => z.uid == porduitId));
var project = Builders<Example>.Project.ElemMatch(
x => x.Family,
y => y.Countries.Any(z => z.uid == porduitId)
);
var examples = await collection.filter(filter).Project<Example>(project).toListAsync();
Using the aggregate pipeline
var filter = Builders<Example>.Filter.ElemMatch(
x => x.Family,
y => y.Countries.Any(z => z.uid == porduitId));
var project = Builders<ServiceProvider>.Projection.Expression(
x => x.Faimily.Where(y => y.uid == porduitId)
);
var result = await collection
.Aggregate()
.Match(filter)
.Project(project)
.ToListAsync(); //Here result is a list of Iterable<Countries>

Related

Add a field into JSON array C#

Here is my json Array, i want to add a new field in array but i dont know how to loop it
{
"data": {
"pasca": [
{
"code": "PDI1231",
"name": "Water Bottle",
"status": 1,
"price": 2500,
"type": "plastic"
},
{
"code": "PDI9999",
"name": "Soccel Ball",
"status": 1,
"price": 99123,
"type": "plastic"
}
]
}
}
i want to add a new field in pasca array like this
"pasca": [
{
"code": "PDI1231",
"name": "Water Bottle",
"status": 1,
"price": 2500,
"type": "plastic",
"new_field_1": "new value_1",
"new_field_2": "new value_2"
}
]
If you are using Newtosoft's Json.NET it can be done as simple as that:
var jObj = JsonConvert.DeserializeObject<JObject>(json);
foreach(var el in jObj["data"]["pasca"])
{
el["new_field_1"] = "new value_1";
}

How to index NotAnalyzed field type List<string>?

class MyObject{
public string Name{get;set;}
public List<string> Tags{get;set;}
}
/*Create mapping */
client.Map<MyObject>(m =>
m.Properties(props =>
props.String(s =>
s.Name(p => p.Name)
.Path(MultiFieldMappingPath.Full)
.Index(FieldIndexOption.NotAnalyzed)
.Fields(f =>
f.String(ps =>
ps.Name(p => p.Name.Suffix("searchable"))
.Index(FieldIndexOption.Analyzed)
)
)
)
)
);
How to index NotAnalyzed for field Tags same field Name
I want to search exactly one phrase in the Tags field
Example: I want search "elastic search" to find out which object contains exactly that word in the Tags field
Obj1:
{
"Name":"Object 1",
"Tags":["elastic search","how to code"]
}
Obj2:
{
"Name":"Object 2",
"Tags":["elastic","c#"]
}
Obj3:
{
"Name":"Object 2",
"Tags":["learn elastic search","learn C#"]
}
===> Result: Obj 1
Based on your request I will create a test1 index.
PUT test1/doc/1
{
"Name": "Object 1",
"Tags": [
"elastic search",
"how to code"
]
}
PUT test1/doc/2
{
"Name":"Object 2",
"Tags":["elastic","c#"]
}
So I will write query to fetch the exact term elastic search as you mentioned in your example.
GET test1/doc/_search
{
"query": {
"term": {
"Tags.keyword":
"elastic search"
}
}
}
So the result is for the below query is
curl -XGET "http://localhost:9200/test1/doc/_search"
{
"took": 0,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 1,
"hits": [
{
"_index": "test1",
"_type": "doc",
"_id": "2",
"_score": 1,
"_source": {
"Name": "Object 2",
"Tags": [
"elastic",
"c#"
]
}
},
{
"_index": "test1",
"_type": "doc",
"_id": "1",
"_score": 1,
"_source": {
"Name": "Object 1",
"Tags": [
"elastic search",
"how to code"
]
}
}
]
}
}
So now the query to fetch documents based on your field.
curl -XGET "http://localhost:9200/test1/doc/_search" -H 'Content-Type: application/json' -d'
{
"query": {
"term": {
"Tags.keyword":
"elastic search"
}
}
}'
And the result is
{
"took": 0,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.2876821,
"hits": [
{
"_index": "test1",
"_type": "doc",
"_id": "1",
"_score": 0.2876821,
"_source": {
"Name": "Object 1",
"Tags": [
"elastic search",
"how to code"
]
}
}
]
}
}
Hope it works. Let me know if you are still facing any issues.

MongoDb: Rename a property in a complex document

We have documents saving to MongoDb. The problem is that one of our sub-documents has an Id property that is getting returned as _id, which is causing serialize/deserialize issues with the C# driver due to how it interprets Id fields (see http://mongodb.github.io/mongo-csharp-driver/2.0/reference/bson/mapping/)
I would like to rename the property from Id to SetId, but our data is fairly dynamic and simple field rename solutions that I've seen elsewhere do not apply. Here's an example of some heavily edited simple data:
{
"Id": "5a6238dbccf20b38b0db6cf2",
"Title": "Simple Document",
"Layout": {
"Name": "Simple Document Layout",
"Tabs": [
{
"Name": "Tab1",
"Sections": [
{
"Name": "Tab1-Section1",
"Sets": [
{
"Id": 1
}
]
}
]
}
]
}
}
Compare with more complex data:
{
"Id": "5a6238dbccf20b38b0db6abc",
"Title": "Complex Document",
"Layout": {
"Name": "Complex Document Layout",
"Tabs": [
{
"Name": "Tab1",
"Sections": [
{
"Name": "Tab1-Section1",
"Sets": [
{
"Id": 1
}
]
},
{
"Name": "Tab1-Section2",
"Sets": [
{
"Id": 1
}
]
}
]
},
{
"Name": "Tab2",
"Sections": [
{
"Name": "Tab2-Section1",
"Sets": [
{
"Id": 1
}
]
}
]
},
{
"Name": "Tab3",
"Sections": [
{
"Name": "Tab3-Section1",
"Sets": [
{
"Id": 1
},
{
"Id": 2
}
]
}
]
}
]
}
}
Note that the Set.Id field can be on multiple tabs on multiple sections with multiple sets. I just don't know how to approach a query to handle renaming data at all these levels.
I took #Veerum's advice and did a manual iteration over the collection with something like this:
myCol = db.getCollection('myCol');
myCol.find({ "Layout.Tabs.Sections.Sets._id": {$exists: true} }).forEach(function(note) {
for(tab = 0; tab != note.Layout.Tabs.length; ++tab) {
for(section = 0; section != note.Layout.Tabs[tab].Sections.length; ++section) {
for(set = 0; set != note.Layout.Tabs[tab].Sections[section].Sets.length; ++set) {
note.Layout.Tabs[tab].Sections[section].Sets[set].SetId = NumberInt(note.Layout.Tabs[tab].Sections[section].Sets[set]._id);
delete note.Layout.Tabs[tab].Sections[section].Sets[set]._id
}
}
}
myCol.update({ _id: note._id }, note);
});
Perhaps there is a more efficient way, but we are still on Mongo v3.2 and it seems to work well.

Parsing LuisResult to get values field

I have a LuisResult variable called result that has JSON info like
{
"query": "what is twenty * three",
"topScoringIntent": {
"intent": "Multiplication",
"score": 0.740870655
},
"intents": [
{
"intent": "Multiplication",
"score": 0.740870655
},
{
"intent": "Subtraction",
"score": 0.04339512
},
{
"intent": "None",
"score": 0.0164503977
},
{
"intent": "addition",
"score": 0.0126439808
},
{
"intent": "Division",
"score": 0.0108866822
}
],
"entities": [
{
"entity": "twenty",
"type": "builtin.number",
"startIndex": 8,
"endIndex": 13,
"resolution": {
"value": "20"
}
},
{
"entity": "three",
"type": "builtin.number",
"startIndex": 17,
"endIndex": 21,
"resolution": {
"value": "3"
}
}
]
}
I'm trying to access the "value" field under "resolution" since it converts string representations of numbers to digit representation. At the moment I'm just trying to get the first value. I've tried to extract the value this way
var valuesEntity = result.Entities; //IList of all entities
string s = "";
s = valuesEntity[i].Resolution.Values.ToString(); //extract value field??
await context.PostAsync($"{s}"); //post to emulator
This prints out System.Collections.Generic.Dictionary`2+ValueCollection[System.String,System.String]
to me. What am I missing to be able to get the "values" field?
Try
valuesEntity[i].Resolution.Values[0].ToString();
Values is a collection of strings.
You can also use linq and do:
valuesEntity[i].Resolution.Values.FirstOrDefault();

JToken get a specific value

I have following JToken output. How can I retrieve the 'value' here from TenantID which should be 1 in this case?
{[
{
"value": 1,
"metadata": {
"userType": 0,
"flags": 8,
"type": {
"type": "INT4",
"name": "Int",
"id": 56
},
"colName": "TenantID"
}
}
]}
This is my current code :
JToken value;
if (usr.Profile.TryGetValue("tenantid", out value))
{
JObject inner = value["value"].Value<JObject>(); //not working with null error
User.TenantID = (string)value;
}
User.obj = usr.Profile;
EDIT - please find below the complete JToken output :
{[
{
"value": 1,
"metadata": {
"userType": 0,
"flags": 8,
"type": {
"type": "INT4",
"name": "Int",
"id": 56
},
"colName": "TenantID"
}
}
]}
Count: 1
First (Newtonsoft.Json.Linq.JContainer): {{
"value": 1,
"metadata": {
"userType": 0,
"flags": 8,
"type": {
"type": "INT4",
"name": "Int",
"id": 56
},
"colName": "TenantID"
}
}}
First (Newtonsoft.Json.Linq.JToken): {{
"value": 1,
"metadata": {
"userType": 0,
"flags": 8,
"type": {
"type": "INT4",
"name": "Int",
"id": 56
},
"colName": "TenantID"
}
}}
HasValues: true
IsReadOnly: false
Last (Newtonsoft.Json.Linq.JContainer): {{
`"value": 1,
"metadata": {
"userType": 0,
"flags": 8,
"type": {
"type": "INT4",
"name": "Int",
"id": 56
},
"colName": "TenantID"
}
}}
Last (Newtonsoft.Json.Linq.JToken): {{
"value": 1,
"metadata": {
"userType": 0,
"flags": 8,
"type": {
"type": "INT4",
"name": "Int",
"id": 56
},
"colName": "TenantID"
}
}}
Next: (null)
Parent: {"tenantid": [
{
"value": 1,
"metadata": {
"userType": 0,
"flags": 8,
"type": {
"type": "INT4",
"name": "Int",
"id": 56
},
"colName": "TenantID"
}
}
]}
Path: "tenantid"
Previous: (null)
Static members:
Non-public members:
IEnumerator:
Root: {{
"name": "Rx Sidhu",
"given_name": "Rx",
"family_name": "Sidhu",
"locale": "en_US",
"emails": [
"ranxdeep#xxx.com",
"ranxdeep#xxx.com",
"ranxdeep#hx.com"
],
"nickname": "ranxdeep#xxx.com",
"email": "ranxdeep#xxx.com",
"picture": "https://apis.live.net/v5.0/f1xxxxxx/picture",
"roles": [
"Account Admin",
"Admin"
],
"tenantid": [
{
"value": 1,
"metadata": {
"userType": 0,
"flags": 8,
"type": {
"type": "INT4",
"name": "Int",
"id": 56
},
"colName": "TenantID"
}
}
],
"email_verified": true,
"clientID": "wxxxvC8",
"updated_at": "2015-07-15T16:26:30.526Z",
"user_id": "windowslive|f1axxxac",
"identities": [
{
"access_token": "EwBwAq1",
"provider": "windowslive",
"user_id": "f1aexxxxxac",
"connection": "windowslive",
"isSocial": true
}
],
"created_at": "2015-07-01T06:08:21.358Z"
}}
Type: 2
I need to check if the tenantID actually exists and then get value, else return null or 0.
You should be able to do:
JObject jObject = JObject.Parse(...);
JToken value = jObject.SelectToken("value");
You parse your object, then the inner contents should be exposed in which you can leverage the SelectToken method to find that specific value.
To build it out a bit, you could potentially do:
public static JToken FindToken<T>(string key, T value)
{
string serialized = NewtonsoftJsonSerializer.Instance.Serialize(value);
var jObject = JObject.Parse(serialized);
var jToken = jObject.SelectToken(key);
if(jToken != null)
return jToken;
return null;
}
I still cannot get the overall picture of your JSON, though have a look at this. It may help you.
var str = #"{
""x"": [{
""value"": 1,
""metadata"": {
""userType"": 0,
""flags"": 8,
""type"": {
""type"":""INT4"",
""name"":""Int"",
""id"": 56
},
""colName"":""TenantID""
}
}
]
}";
var parentJObject = JObject.Parse(str);
var xJArray = (JArray)parentJObject["x"];
// first item in JArray which is the object of interest
// look for the appropriate index of the JObject of your data
var firstJTokenInxJArray = (JObject)xJArray[0];
Console.WriteLine(firstJTokenInxJArray["value"].ToString());
I got what I was looking for :
JToken value;
if (usr.Profile.TryGetValue("tenantid", out value))
{
User.TenantID = (int)value [0] ["value"];
}

Categories