I have a JObject with a JSON like it:
{"name" : "user1", "groups" : ["group 1", "group2"]}
I would like to delete one group by the name. So I have a code like this:
JObject userJson = JObject.Parse(user);
JArray groups = userJson["groups"] as JArray;
JToken group = new JValue (groupName);
groups.Remove(group);
However the method JArray.remove(Jtoken item) return false (that means that it couldn't be deleted). Here the information:
https://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Linq_JArray_Remove.htm
So tried to set the parameter like JToken group = new JValue (groupName);
JToken group = new JValue (groupName); as JToken
and JValue group = new JValue (groupName);
But it doesnt work :S
This guy explains JToken hierarchy very good but I don't know what I'm not doing right.
The basic issue is that the JToken
hierarchy is doubly-connected graph. That is, each token knows its Parent
and each parent knows its Children
. Indeed, if you add a token that already has a parent to a parent, it gets cloned, as explained here.
Thus, since every token knows its parent, when you try to remove a token from a parent, Json.NET might do one of two things:
And, in fact, Json.NET chooses the former option. Jarray.Remove(JToken item)
calls JContainer.RemoveItem()
which calls JArray.IndexOfItem()
to determine the index of the item to remove. This method, in turn, uses reference equality:
internal override int IndexOfItem(JToken item)
{
return _values.IndexOfReference(item);
}
Since your JToken group = new JValue (groupName)
does not belong to the JArray groups
, it is not removed.
So, what are your options to remove a JSON array item by value? You could:
Search using LINQ:
groups.Where(i => i.Type == JTokenType.String && (string)i == groupName).ToList().ForEach(i => i.Remove());
Search using JTokenEqualityComparer
, which can be used to search for complex objects as well as primitive values:
var comparer = new JTokenEqualityComparer();
groups.Where(i => comparer.Equals(i, group)).ToList().ForEach(i => i.Remove());
Search using SelectTokens()
:
userJson.SelectTokens(string.Format("groups[?(@ == '{0}')]", groupName)).ToList().ForEach(i => i.Remove());
SelectTokens()
supports the JSONPath query syntax which enables searching though arrays for matching items.
Finally, a note about the documentation for RemoveItem()
. It states (italics added):
JArray.Remove Method (JToken)
Removes the first occurrence of a specific object from the JArray.
Since we have seen that a token that has a parent is cloned when added to a parent, it seems there can only ever be one occurrence of any token within a given parent. Yet the documentation seems to imply otherwise; I would hazard a guess that this particular documentation sentence is obsolete and dates from some much earlier version of Json.NET where the same token could appear within a parent multiple times.