JObject.ToBsonDocument删除值

Ric*_*ney 9 json.net mlab

我正在将原始JSON插入到集合中,并发现存储在数据库中的内容缺少值.例如,我的集合是BsonDocuments的集合:

_products = database.GetCollection<BsonDocument>("products");
Run Code Online (Sandbox Code Playgroud)

将JSON插入集合的代码:

public int AddProductDetails(JObject json)
{
    var doc = json.ToBsonDocument(DictionarySerializationOptions.Document);
    _products.Insert(doc);
}
Run Code Online (Sandbox Code Playgroud)

传入的JSON如下所示:

{"Id":1,"Tags":["book","database"],"Name":"Book Name","Price":12.12}

但是,集合中持久存在的只是没有值的属性.

{
  "Id": 1,
  "Tags": [
    "book",
    "database"
  ],
  "Name": "Book Name",
  "Price": 12.12
}
Run Code Online (Sandbox Code Playgroud)

为什么值被删除?

Ric*_*ney 16

这就是我所期待的.

    public int AddProductDetails(JObject json)
    {
        BsonDocument doc = BsonDocument.Parse(json.ToString());
        _products.Insert(doc);
    }
Run Code Online (Sandbox Code Playgroud)

  • 这很好,但有更高效的版本[3年]?复制到String可能是大型JSON的"昂贵"操作? (5认同)
  • @JamesWoodall - 5 年了 :-) 你可以看看我的回答 (2认同)

小智 8

当我有一个带有JObject类型属性的C#类时遇到了这个问题.

我的解决方案是为MondoDB创建JObjectSerializer,将属性添加到属性,以便Mongo Serializer使用它.我假设如果我努力尝试,我可以在Mongo中注册下面的Serializer作为此类型的全局Serializer.

[BsonSerializer(typeof(JObjectSerializer))]
public JObject AdditionalData { get; set; }
Run Code Online (Sandbox Code Playgroud)

  • `BsonSerializer.RegisterSerializer(new JObjectSerializer());` 就是你要找的。只需将它贴在您的应用程序启动附近的某个位置,您就不需要属性注释。 (2认同)

Sim*_*ier 6

使用JObject.ToString,BsonDocument.Parse等时的问题是性能不是很好,因为您多次执行相同的操作,进行字符串分配、解析等。

因此,我编写了一个将 a 转换JObject为 an IEnumerable<KeyValuePair<string, object>>(仅使用枚举)的函数,这是一个BsonDocument构造函数可用的类型。这是代码:

public static BsonDocument ToBsonDocument(this JObject jo)
{
    if (jo == null)
        return null;

    return new BsonDocument(ToEnumerableWithObjects(jo));
}

public static IEnumerable<KeyValuePair<string, object>> ToEnumerableWithObjects(this JObject jo)
{
    if (jo == null)
        return Enumerable.Empty<KeyValuePair<string, object>>();

    return new JObjectWrapper(jo);
}

private class JObjectWrapper : IEnumerable<KeyValuePair<string, object>>
{
    private JObject _jo;

    public JObjectWrapper(JObject jo)
    {
        _jo = jo;
    }

    public IEnumerator<KeyValuePair<string, object>> GetEnumerator() => new JObjectWrapperEnumerator(_jo);
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

    public static object ToValue(JToken token)
    {
        object value;
        switch (token.Type)
        {
            case JTokenType.Object:
                value = new JObjectWrapper((JObject)token);
                break;

            case JTokenType.Array:
                value = new JArrayWrapper((JArray)token);
                break;

            default:
                if (token is JValue jv)
                {
                    value = ((JValue)token).Value;
                }
                else
                {
                    value = token.ToString();
                }
                break;
        }
        return value;
    }
}

private class JArrayWrapper : IEnumerable
{
    private JArray _ja;

    public JArrayWrapper(JArray ja)
    {
        _ja = ja;
    }

    public IEnumerator GetEnumerator() => new JArrayWrapperEnumerator(_ja);
}

private class JArrayWrapperEnumerator : IEnumerator
{
    private IEnumerator<JToken> _enum;

    public JArrayWrapperEnumerator(JArray ja)
    {
        _enum = ja.GetEnumerator();
    }

    public object Current => JObjectWrapper.ToValue(_enum.Current);
    public bool MoveNext() => _enum.MoveNext();
    public void Reset() => _enum.Reset();
}

private class JObjectWrapperEnumerator : IEnumerator<KeyValuePair<string, object>>
{
    private IEnumerator<KeyValuePair<string, JToken>> _enum;

    public JObjectWrapperEnumerator(JObject jo)
    {
        _enum = jo.GetEnumerator();
    }

    public KeyValuePair<string, object> Current => new KeyValuePair<string, object>(_enum.Current.Key, JObjectWrapper.ToValue(_enum.Current.Value));
    public bool MoveNext() => _enum.MoveNext();
    public void Dispose() => _enum.Dispose();
    public void Reset() => _enum.Reset();
    object IEnumerator.Current => Current;
}
Run Code Online (Sandbox Code Playgroud)

  • 迄今为止最高效的答案。奇迹般有效。 (2认同)