JavaEar 专注于收集分享传播有价值的技术资料

Filter Json response from Facebook

问题描述


英文原文

I'm trying to filter Json response using Json2Linq of Json.Net but error was occurred during filtering says "Cannot access child value on Newtonsoft.Json.Linq.JProperty." below are my code on C#

   JObject rss = JObject.Parse(userJson);

        try
        {
            var FriendsLikes = from c in rss["friends"].First()["data"]
                               .SelectMany(l => l["likes"]
                               .Select(d => d["data"]).Where(r => r["id"].Value<string>() == "475729939105078")).Values<string>()
                               group c by c into g
                               orderby g.Count() descending
                               select new { FriendsLikes = g.Key };

            foreach (var item in FriendsLikes)
            {
                System.Diagnostics.Debug.WriteLine(item.FriendsLikes);
            }
        }
        catch (System.Exception e)
        {
            System.Diagnostics.Debug.WriteLine(e.Message);
        }

Facebook Json Response

{
"id": "999999999084775",
"name": "Alex Xx",
"first_name": "Alex",
"last_name": "Xx",
"gender": "male",
"link": "https://www.facebook.com/app_scoped_user_id/101999999999999/",
"locale": "en_US",
"email": "alexxxx@gmail.com",
"picture": {
    "data": {
        "url": "https://scontent.xx.fbcdn.net/v/t1.0-1/p50x50/18341660_101370733774524_7009999999999957463_n.jpg?oh=ec8675dfe23bbda00b6048647af62875&oe=59C0F7DF",
        "is_silhouette": false
    }
},
"friends": {
    "data": [{
        "id": "10213045626997937",
        "name": "Jayson Raga",
        "first_name": "Jayson",
        "last_name": "Ragasa",
        "gender": "male",
        "link": "https://www.facebook.com/app_scoped_user_id/10213045626997937/",
        "locale": "en_US",
        "picture": {
            "data": {
                "url": "https://scontent.xx.fbcdn.net/v/t1.0-1/p50x50/16114608_10211941851924250_4611916174586601978_n.jpg?oh=de4c0a7839e7e9e7ef6e29e18b885ef898&oe=59A99999",
                "is_silhouette": false
            }
        },
        "likes": {
            "data": [{
                "live_videos": {
                    "data": [{
                        "from": {
                            "name": "MyBeat",
                            "id": "475728822105078"
                        },
                        "permalink_url": "/MyBeat/videos/1283448691726531/",
                        "description": "@[141752355816253]:behind the decks live",
                        "creation_time": "2016-07-03T17:20:49+0000",
                        "id": "1261428671666530"
                    }]
                },
                "id": "475723939105078"
            }]
        }
    }]
},

}

My goal in my code is to filter all my friends like and return all likes from ID:475723939105078


中文翻译

I'm trying to filter Json response using Json2Linq of Json.Net but error was occurred during filtering says "Cannot access child value on Newtonsoft.Json.Linq.JProperty." below are my code on C#

   JObject rss = JObject.Parse(userJson);

        try
        {
            var FriendsLikes = from c in rss["friends"].First()["data"]
                               .SelectMany(l => l["likes"]
                               .Select(d => d["data"]).Where(r => r["id"].Value<string>() == "475729939105078")).Values<string>()
                               group c by c into g
                               orderby g.Count() descending
                               select new { FriendsLikes = g.Key };

            foreach (var item in FriendsLikes)
            {
                System.Diagnostics.Debug.WriteLine(item.FriendsLikes);
            }
        }
        catch (System.Exception e)
        {
            System.Diagnostics.Debug.WriteLine(e.Message);
        }

Facebook Json Response

{
"id": "999999999084775",
"name": "Alex Xx",
"first_name": "Alex",
"last_name": "Xx",
"gender": "male",
"link": "https://www.facebook.com/app_scoped_user_id/101999999999999/",
"locale": "en_US",
"email": "alexxxx@gmail.com",
"picture": {
    "data": {
        "url": "https://scontent.xx.fbcdn.net/v/t1.0-1/p50x50/18341660_101370733774524_7009999999999957463_n.jpg?oh=ec8675dfe23bbda00b6048647af62875&oe=59C0F7DF",
        "is_silhouette": false
    }
},
"friends": {
    "data": [{
        "id": "10213045626997937",
        "name": "Jayson Raga",
        "first_name": "Jayson",
        "last_name": "Ragasa",
        "gender": "male",
        "link": "https://www.facebook.com/app_scoped_user_id/10213045626997937/",
        "locale": "en_US",
        "picture": {
            "data": {
                "url": "https://scontent.xx.fbcdn.net/v/t1.0-1/p50x50/16114608_10211941851924250_4611916174586601978_n.jpg?oh=de4c0a7839e7e9e7ef6e29e18b885ef898&oe=59A99999",
                "is_silhouette": false
            }
        },
        "likes": {
            "data": [{
                "live_videos": {
                    "data": [{
                        "from": {
                            "name": "MyBeat",
                            "id": "475728822105078"
                        },
                        "permalink_url": "/MyBeat/videos/1283448691726531/",
                        "description": "@[141752355816253]:behind the decks live",
                        "creation_time": "2016-07-03T17:20:49+0000",
                        "id": "1261428671666530"
                    }]
                },
                "id": "475723939105078"
            }]
        }
    }]
},

}

My goal in my code is to filter all my friends like and return all likes from ID:475723939105078

I'm trying to filter Json response using Json2Linq of Json.Net but error was occurred during filtering says "Cannot access child value on Newtonsoft.Json.Linq.JProperty." below are my code on C#

   JObject rss = JObject.Parse(userJson);

        try
        {
            var FriendsLikes = from c in rss["friends"].First()["data"]
                               .SelectMany(l => l["likes"]
                               .Select(d => d["data"]).Where(r => r["id"].Value<string>() == "475729939105078")).Values<string>()
                               group c by c into g
                               orderby g.Count() descending
                               select new { FriendsLikes = g.Key };

            foreach (var item in FriendsLikes)
            {
                System.Diagnostics.Debug.WriteLine(item.FriendsLikes);
            }
        }
        catch (System.Exception e)
        {
            System.Diagnostics.Debug.WriteLine(e.Message);
        }

Facebook Json Response

{
"id": "999999999084775",
"name": "Alex Xx",
"first_name": "Alex",
"last_name": "Xx",
"gender": "male",
"link": "https://www.facebook.com/app_scoped_user_id/101999999999999/",
"locale": "en_US",
"email": "alexxxx@gmail.com",
"picture": {
    "data": {
        "url": "https://scontent.xx.fbcdn.net/v/t1.0-1/p50x50/18341660_101370733774524_7009999999999957463_n.jpg?oh=ec8675dfe23bbda00b6048647af62875&oe=59C0F7DF",
        "is_silhouette": false
    }
},
"friends": {
    "data": [{
        "id": "10213045626997937",
        "name": "Jayson Raga",
        "first_name": "Jayson",
        "last_name": "Ragasa",
        "gender": "male",
        "link": "https://www.facebook.com/app_scoped_user_id/10213045626997937/",
        "locale": "en_US",
        "picture": {
            "data": {
                "url": "https://scontent.xx.fbcdn.net/v/t1.0-1/p50x50/16114608_10211941851924250_4611916174586601978_n.jpg?oh=de4c0a7839e7e9e7ef6e29e18b885ef898&oe=59A99999",
                "is_silhouette": false
            }
        },
        "likes": {
            "data": [{
                "live_videos": {
                    "data": [{
                        "from": {
                            "name": "MyBeat",
                            "id": "475728822105078"
                        },
                        "permalink_url": "/MyBeat/videos/1283448691726531/",
                        "description": "@[141752355816253]:behind the decks live",
                        "creation_time": "2016-07-03T17:20:49+0000",
                        "id": "1261428671666530"
                    }]
                },
                "id": "475723939105078"
            }]
        }
    }]
},

}

My goal in my code is to filter all my friends like and return all likes from ID:475723939105078

I'm trying to filter Json response using Json2Linq of Json.Net but error was occurred during filtering says "Cannot access child value on Newtonsoft.Json.Linq.JProperty." below are my code on C#

   JObject rss = JObject.Parse(userJson);

        try
        {
            var FriendsLikes = from c in rss["friends"].First()["data"]
                               .SelectMany(l => l["likes"]
                               .Select(d => d["data"]).Where(r => r["id"].Value<string>() == "475729939105078")).Values<string>()
                               group c by c into g
                               orderby g.Count() descending
                               select new { FriendsLikes = g.Key };

            foreach (var item in FriendsLikes)
            {
                System.Diagnostics.Debug.WriteLine(item.FriendsLikes);
            }
        }
        catch (System.Exception e)
        {
            System.Diagnostics.Debug.WriteLine(e.Message);
        }

Facebook Json Response

{
"id": "999999999084775",
"name": "Alex Xx",
"first_name": "Alex",
"last_name": "Xx",
"gender": "male",
"link": "https://www.facebook.com/app_scoped_user_id/101999999999999/",
"locale": "en_US",
"email": "alexxxx@gmail.com",
"picture": {
    "data": {
        "url": "https://scontent.xx.fbcdn.net/v/t1.0-1/p50x50/18341660_101370733774524_7009999999999957463_n.jpg?oh=ec8675dfe23bbda00b6048647af62875&oe=59C0F7DF",
        "is_silhouette": false
    }
},
"friends": {
    "data": [{
        "id": "10213045626997937",
        "name": "Jayson Raga",
        "first_name": "Jayson",
        "last_name": "Ragasa",
        "gender": "male",
        "link": "https://www.facebook.com/app_scoped_user_id/10213045626997937/",
        "locale": "en_US",
        "picture": {
            "data": {
                "url": "https://scontent.xx.fbcdn.net/v/t1.0-1/p50x50/16114608_10211941851924250_4611916174586601978_n.jpg?oh=de4c0a7839e7e9e7ef6e29e18b885ef898&oe=59A99999",
                "is_silhouette": false
            }
        },
        "likes": {
            "data": [{
                "live_videos": {
                    "data": [{
                        "from": {
                            "name": "MyBeat",
                            "id": "475728822105078"
                        },
                        "permalink_url": "/MyBeat/videos/1283448691726531/",
                        "description": "@[141752355816253]:behind the decks live",
                        "creation_time": "2016-07-03T17:20:49+0000",
                        "id": "1261428671666530"
                    }]
                },
                "id": "475723939105078"
            }]
        }
    }]
},

}

My goal in my code is to filter all my friends like and return all likes from ID:475723939105078

1个回答

    最佳答案

  1. 英文原文

    First, a preliminary problem. You are querying for r["id"].Value<string>() == "475729939105078" but the ID value in the JSON is actually:

                "id": "475723939105078"
    

    These need to be the same. I'll assume this is a typo in the question.

    Your query consists of several parts -

    1. You are looping through all like data objects inside nested arrays "friends.data[*].likes.data[*]", where [*] indicates an array index wildcard using JSONPath syntax.

    2. You are filtering those objects with id == "475723939105078"

    3. You seem to be grouping duplicates and ordering by count -- though I'm not sure of this since .Values<string>() is intended to get the values of a primitive properties whereas the like.data objects are not, in fact primitives, so this part of the query fails.

    Also, you are mixing LINQ and Lambda syntax, which makes things more confusing. I'd suggest choosing one and sticking with it.

    The first two parts of the query can be accomplished using LINQ syntax as follows:

            var id = "475723939105078";
            var friendLikesFiltered 
                = from f in rss["friends"]["data"]  // Loop through all entries f in friends.data
                  from l in f["likes"]["data"]      // Then loop all entries in likes.data
                  where (string)l["id"] == id       // where like.id == friendId
                  select l;
    

    Or using lambda:

            var id = "475723939105078";
            var friendLikesFiltered 
                = rss["friends"]["data"]
                .SelectMany(f => f["likes"]["data"])
                .Where(l => (string)l["id"] == id);
    

    And finally using SelectTokens() with JSONPath:

            var id = "475723939105078";
            var friendLikesFiltered
                = rss.SelectTokens("friends.data[*].likes.data[*]")
                .Where(l => (string)l["id"] == id);
    

    For comparison, in your query, the "Cannot access child value on Newtonsoft.Json.Linq.JProperty." error is caused by the fact that, when you do rss["friends"]["data"].First().SelectMany(l => l["likes"]) the extra First() grabs the first array entry so the SelectMany() ends up looping through the like property values -- which is one level too deep in the token hierarchy.

    As for grouping, your JSON doesn't show an example of duplicated like data, but you can always JTokenEqualityComparer to to identify and group identical JSON objects:

            var friendLikes =
                friendLikesFiltered
                .GroupBy(l => l, new JTokenEqualityComparer())
                .OrderBy(g => g.Count())
                .Select(g => g.Key);
    

    (Here I use lambda syntax in order to use the custom IEqualityComparer<JToken>.)

    Sample fiddle showing all three versions.


    中文翻译

    First, a preliminary problem. You are querying for r["id"].Value<string>() == "475729939105078" but the ID value in the JSON is actually:

                "id": "475723939105078"
    

    These need to be the same. I'll assume this is a typo in the question.

    Your query consists of several parts -

    1. You are looping through all like data objects inside nested arrays "friends.data[*].likes.data[*]", where [*] indicates an array index wildcard using JSONPath syntax.

    2. You are filtering those objects with id == "475723939105078"

    3. You seem to be grouping duplicates and ordering by count -- though I'm not sure of this since .Values<string>() is intended to get the values of a primitive properties whereas the like.data objects are not, in fact primitives, so this part of the query fails.

    Also, you are mixing LINQ and Lambda syntax, which makes things more confusing. I'd suggest choosing one and sticking with it.

    The first two parts of the query can be accomplished using LINQ syntax as follows:

            var id = "475723939105078";
            var friendLikesFiltered 
                = from f in rss["friends"]["data"]  // Loop through all entries f in friends.data
                  from l in f["likes"]["data"]      // Then loop all entries in likes.data
                  where (string)l["id"] == id       // where like.id == friendId
                  select l;
    

    Or using lambda:

            var id = "475723939105078";
            var friendLikesFiltered 
                = rss["friends"]["data"]
                .SelectMany(f => f["likes"]["data"])
                .Where(l => (string)l["id"] == id);
    

    And finally using SelectTokens() with JSONPath:

            var id = "475723939105078";
            var friendLikesFiltered
                = rss.SelectTokens("friends.data[*].likes.data[*]")
                .Where(l => (string)l["id"] == id);
    

    For comparison, in your query, the "Cannot access child value on Newtonsoft.Json.Linq.JProperty." error is caused by the fact that, when you do rss["friends"]["data"].First().SelectMany(l => l["likes"]) the extra First() grabs the first array entry so the SelectMany() ends up looping through the like property values -- which is one level too deep in the token hierarchy.

    As for grouping, your JSON doesn't show an example of duplicated like data, but you can always JTokenEqualityComparer to to identify and group identical JSON objects:

            var friendLikes =
                friendLikesFiltered
                .GroupBy(l => l, new JTokenEqualityComparer())
                .OrderBy(g => g.Count())
                .Select(g => g.Key);
    

    (Here I use lambda syntax in order to use the custom IEqualityComparer<JToken>.)

    Sample fiddle showing all three versions.