LINQ to JSON - Querying an array - linq

I need to select users that have a "3" in their json array.
{
"People":[
{
"id" : "123",
"firstName" : "Bill",
"lastName" : "Gates",
"roleIds" : {
"int" : ["3", "9", "1"]
}
},
{
"id" : "456",
"firstName" : "Steve",
"lastName" : "Jobs",
"roleIds" : {
"int" : ["3", "1"]
}
},
{
"id" : "789",
"firstName" : "Elon",
"lastName" : "Musk",
"roleIds" : {
"int" : ["3", "7"]
}
},
{
"id" : "012",
"firstName" : "Agatha",
"lastName" : "Christie",
"roleIds" : {
"int" : "2"
}
}
]}
In the end, my results should be Elon Musk & Steve Jobs. This is the code that I used (& other variations):
var roleIds = pplFeed["People"]["roleIds"].Children()["int"].Values<string>();
var resAnAssocInfo = pplFeed["People"]
.Where(p => p["roleIds"].Children()["int"].Values<string>().Contains("3"))
.Select(p => new
{
id = p["id"],
FName = p["firstName"],
LName = p["lastName"]
}).ToList();
I'm getting the following error:
"Accessed JArray values with invalid key value: "roleIds". Int32 array index expected"
I changed .Values<string>() to .Values<int>() and still no luck.
What am I doing wrong?

You are pretty close. Change your Where clause from this:
.Where(p => p["roleIds"].Children()["int"].Values<string>().Contains("3"))
to this:
.Where(p => p["roleIds"]["int"].Children().Contains("3"))
and you will get you the result you want (although there are actually three users in your sample data with a role id of "3", not two).
However, there's another issue that you might hit for which this code still won't work. You'll notice that for Agatha Christie, the value of int is not an array like the others, it is a simple string. If the value will sometimes be an array and sometimes not, then you need a where clause that can handle both. Something like this should work:
.Where(p => p["roleIds"]["int"].Children().Contains(roleId) ||
p["roleIds"]["int"].ToString() == roleId)
...where roleId is a string containing the id you are looking for.
Fiddle: https://dotnetfiddle.net/Zr1b6R

The problem is that not all objects follow the same interface. The last item in that list has a single string value in the roleIds.int property while all others has an array. You need to normalize that property and then do the check. It'll be easiest if they were all arrays.
You should be able to do this:
var roleId = "3";
var query =
from p in pplFeed["People"]
let roleIds = p.SelectToken("roleIds.int")
let normalized = roleIds.Type == JTokenType.Array ? roleIds : new JArray(roleIds)
where normalized.Values().Contains(roleId)
select new
{
id = p["id"],
FName = p["firstName"],
LName = p["lastName"],
};

Related

Can't select sub aggregation in Nest

I get these results in my Elastic query:
"Results" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "73c47133-8656-45e7-9499-14f52df07b70",
"doc_count" : 1,
"foo" : {
"doc_count" : 40,
"bar" : {
"doc_count" : 1,
"customscore" : {
"value" : 10.496919917864476
}
}
}
}
]
I am trying to get a list of anonymous objects with the key field as the key and customscore field as the value.
No matter what I try, I can't seem to write code in Nest that accesses the customscore value. Apparently, I'm the very first person in the world to use nested Aggregations with the Nest library. Either that, or the documentation is very lacking. I can easily reach the Buckets:
response?.Aggregations.Terms("Results").Buckets;
But I have no idea what to do with this object. Buckets contains several objects, which I would assume I could navigate by doing this:
bucketObject["foo"]["bar"]["customscore"]
But apparently not. I have found solutions that use for loops, solutions with long Linq queries, and all of them seem to return null for me. What am I missing?
Assuming the following query, which I think would match the response in the question
var client = new ElasticClient();
var response = client.Search<object>(s => s
.Index("some_index")
.Aggregations(a => a
.Terms("Results", t => t
.Field("some_field")
.Aggregations(aa => aa
.Filter("foo", f => f
.Filter(q => q.MatchAll())
.Aggregations(aaa => aaa
.Filter("bar", ff => ff
.Filter(q => q.MatchAll())
.Aggregations(aaaa => aaaa
.ValueCount("customscore", vc => vc
.Field("some_other_field")
)
)
)
)
)
)
)
)
);
To get a collection of anonymous types would be
var kvs = response.Aggregations.Terms("Results").Buckets
.Select(b => new
{
key = b.Key,
value = b.Filter("foo").Filter("bar").ValueCount("customscore").Value
});
.Aggregations exposes methods that convert the IAggregate response to the expected type

Spring MongoDB BasicQuery not working with projection

I have following BasicQuery
BasicQuery query2 = new BasicQuery("{status:{$in:['APPROVED','NEW','OPEN']}},{siteId:1,_id:0}");
Where BasicQuery is a class from SpringData mongoDb org.springframework.data.mongodb.core.query.BasicQuery. While doing the debug the above query get compiled into
Query: { "status" : { "$in" : [ "APPROVED" , "NEW" , "OPEN"]}}, Fields: null, Sort: { }
But it should have been compiled as below
Query: { "status" : { "$in" : [ "APPROVED" , "OPEN" , "NEW"]}}, Fields: { "siteId" : 1 , "_id" : 0}, Sort: null
If you notice, fields are still missing into compiled BasicQuery. Please help how i can have project in BasicQuery. I can have projection by using Query as below.
Query query = new Query();
query.addCriteria(Criteria.where(STATUS).in(validStatus));
query.fields().include("siteId").exclude("_id");
My query is how i can achieve the same using BasicQuery.
I guess i got the answer. Instead of using single string argument constructor of BasicQuery we need to use two String argument basic query as follow.
BasicQuery query2 = new BasicQuery("{status:{$in:['APPROVED','NEW','OPEN']}}","{siteId:1,_id:0}");
Above will compile into following query
Query: { "status" : { "$in" : [ "APPROVED" , "OPEN" , "NEW"]}}, Fields: { "siteId" : 1 , "_id" : 0}, Sort: null
BasicQuery query = new BasicQuery("{ $and: [{ studentId: { $in: "+studentIds+" } }, { status: { $ne: '"+studStatus+"'} }] }");
studentIds is an array and studStatus is a string!
Thanks to vashishth

SwiftyJSON won't parse my dictionary

I have a simple array of categories coming from server. Each category is a dictionary.
var json = JSON(json!)
println(json)
for (index: String, subJson: JSON) in json {
println(subJson)
The subjs. printout is:
{
"thumbnailImage" : null,
"isNew" : true,
"id" : 30,
"name" : "Abilities",
"mainImage" : null
}
So shouldn't :
if let extId = subJson["id"].string{
NSLog(subJson["id"].string!)
}
Run and log "30"? It never passes the conditional.
What am I obviously doing wrong?
It was a number, I was casting it to string, it worked with:
subjs.["id].number

Compare three arrays of hashes and get the result without duplicates in ruby?

I m using the fql gem to retrieve the data from facebook. The original array of hashes is like this. Here. When i compare these three arrays of hashes then i want to get the final result in this way:
{
"photo" => [
[0] {
"owner" : "1105762436",
"src_big" : "https://fbcdn-sphotos-b-a.akamaihd.net/hphotos-ak-xap1/t31.0-8/q71/s720x720/10273283_10203050474118531_5420466436365792507_o.jpg",
"caption" : "Rings...!!\n\nView Full Screen.",
"created" : 1398953040,
"modified" : 1398953354,
"like_info" : {
"can_like" : true,
"like_count" : 22,
"user_likes" : true
},
"comment_info" : {
"can_comment" : true,
"comment_count" : 2,
"comment_order" : "chronological"
},
"object_id" : "10203050474118531",
"pid" : "4749213500839034982"
}
],
"comment" => [
[0] {
"text" : "Wow",
"text_tags" : [],
"time" : 1398972853,
"likes" : 1,
"fromid" : "100001012753267",
"object_id" : "10203050474118531"
},
[1] {
"text" : "Woww..",
"text_tags" : [],
"time" : 1399059923,
"likes" : 0,
"fromid" : "100003167704574",
"object_id" : "10203050474118531"
}
],
"users" =>[
[0] {
"id": "1105762436",
"name": "Nilanjan Joshi",
"username": "NilaNJan219"
},
[1] {
"id": "1105762436",
"name": "Ashish Joshi",
"username": "NilaNJan219"
}
]
}
Here is my attempt:
datas = File.read('source2.json')
all_data = JSON.parse(datas)
photos = all_data[0]['fql_result_set'].group_by{|x| x['object_id']}.to_a
comments = all_data[1]['fql_result_set'].group_by{|x| x['object_id']}.to_a
#photos_comments = []
#comments_users = []
#photo_users = []
photos.each do |a|
comments.each do |b|
if a.first == b.first
#photos_comments << {'photo' => a.last, 'comment' => b.last}
else
#comments_users << {'photo' => a.last, 'comment' => ''} unless #photos_comments.include? (a.last)
end
end
end
#photo_users = #photos_comments | #comments_users
#photo_comment_users = {photos_comments: #photo_users }
Here is what i'm getting final result
Still there are duplicates in the final array. I've grouped by the array by object id which is common between the photo and the comment array. But the problem it is only taking those photos which has comments. I'm not getting the way how to find out the photos which don't have the comments.
Also in order to find out the details of the person who has commented, ive users array and the common attribute between comments and users is fromid and id. I'm not able to understand how to get the user details also.
I think this is what you want:
photos = all_data[0]['fql_result_set']
comments = all_data[1]['fql_result_set'].group_by{|x| x['object_id']}
#photo_comment_users = photos.map do |p|
{ 'photo' => p, 'comment' => comments[p['object_id']] || '' }
end
For each photo it takes all the comments with the same object_id, or if none exist - returns ''.
If you want to connect the users too, you can map them by id, and select the relevant ones by the comment:
users = Hash[all_data[2]['fql_result_set'].map {|x| [x['id'], x]}]
#photo_comment_users = photos.map do |p|
{ 'photo' => p, 'comment' => comments[p['object_id']] || '',
'user' => (comments[p['object_id']] || []).map {|c| users[c['formid']]} }
end

update in a nested array using C# Driver in MongoDB

Here is my exact schema:
{
"_id" : ObjectId("4fb4fd04b748611ca8da0d45"),
"Name" : "Agent name",
"City" : "XXXX",
"BranchOffice" : [{
"_id" : ObjectId("4fb4fd04b748611ca8da0d46"),
"Name" : "Branch name",
"City" : "XXXX",
"SubBranch" : [{
"_id" : ObjectId("4fb4fd04b748611ca8da0d47"),
"Name" : "Sub-Branch Name",
"City" : "XXXX"
"Users" : [{
"_id" : ObjectId("4fb4fd04b748611ca8da0d48"),
"Name" : "User",
"City" : "XXXX"
}]
}]
}]
}
Its Inserted successfully in c#. insert code was below but update condition is failed .
I want to update field 3 level and 4 level of array using SubBranch and users
Insert code
IMongoQuery query = Query.And(Query.EQ("_id", new ObjectId(4fb4fd04b748611ca8da0d45)),
Query.EQ("BranchOffice._id", new ObjectId(4fb4fd04b748611ca8da0d46)));
Agent agent = dc.Collection.FindOne(query);
BsonDocument branchOffice = agent.BranchOffice.Find(objId => objId._id == new ObjectId(4fb4fd04b748611ca8da0d46)).ToBsonDocument();
subBranch I had get List object convert to BsonDocument
Files: name,city,_Id, and users for array
BsonDocument subBranchOffice = **subBranch.ToBsonDocument()**;
if (branchOffice.Contains("SubBranch"))
{
if (branchOffice["SubBranch"].IsBsonNull)
{
branchOffice["SubBranch"] = new BsonArray().Add(BsonValue.Create(subBranchOffice));
}
else
{
branchOffice["SubBranch"].AsBsonArray.Add(BsonValue.Create(subBranchOffice));
}
var update = Update.Set("BranchOffice.$.SubBranch",branchOffice["SubBranch"]);
SafeModeResult s = dc.Collection.Update(query, update, UpdateFlags.Upsert,SafeMode.True);
}
Here SafemodeResult is UpdateExisting = true
Here Inserted Option is successfully
next I try to update in else Statement. I am not get it answer
Update code
else
{
var queryEdit = Query.And(Query.EQ("_id", new ObjectId(4fb4fd04b748611ca8da0d45)),
Query.EQ("BranchOffice._id", new ObjectId(4fb4fd04b748611ca8da0d46)),
Query.EQ("SubBranchlist._id", new ObjectId(4fb4fd04b748611ca8da0d47)));
**//Index value 1 or 2 or 3**
var update = Update.Set("BranchOffice.$.SubBranch."index value".Name", "sname").
Set("BranchOffice.$.SubBranch."index value".city", "yyyyy" ?? string.Empty);
SafeModeResult s = dc.Collection.Update(queryEdit, update, UpdateFlags.None,SafeMode.True);
}
Here SafemodeResult is UpdateExisting = False
Here updated Option is fail
Please explain how to solve this probelm and how to update field 2 and 3 level of array
Please show any Example
There's a lot there, but it looks like at least part of your problem is that you've spelled BranchOffice differently between the data and the query you are using to update, also you've missed the hierarchy in SubBranch, so your queryEdit in the last code sample won't match the document. This will;
db.so.find({
_id: ObjectId("4fb4fd04b748611ca8da0d45"),
"BrancheOffice._id": ObjectId("4fb4fd04b748611ca8da0d46"),
"BrancheOffice.SubBranch._id": ObjectId("4fb4fd04b748611ca8da0d47"),
}).toArray()

Resources