【问题标题】:Convert Newtosoft JObject directly to BsonDocument将 Newtosoft JObject 直接转换为 BsonDocument
【发布时间】:2020-05-29 06:51:20
【问题描述】:

尝试使用此示例将JObject 转换为BsonDocument https://www.newtonsoft.com/json/help/html/WriteJTokenToBson.htmBsonWriter 已过时,所以我使用BsonDataWriter

var jObject = JObject.Parse("{\"name\":\"value\"}");

using var writer = new BsonDataWriter(new MemoryStream());
jObject.WriteTo(writer);

var bsonData = writer.ToBsonDocument();

Console.WriteLine(bsonData.ToJson());

输出:

{ "CloseOutput" : true, "AutoCompleteOnClose" : true, "Formatting" : 0, "DateFormatHandling" : 0, "DateTimeZoneHandling" : 3, "StringEscapeHandling" : 0, "FloatFormatHandling" : 0, "DateFormatString" : null
, "Culture" : { "Name" : "", "UseUserOverride" : false }, "DateTimeKindHandling" : 1 }

预期输出是:

{"name": "value"}

我该如何解决?

UPD:我有一个JObject,想直接转成BSONDocument,避免序列化成字符串和字符串解析

【问题讨论】:

    标签: c# mongodb json.net mongodb-.net-driver bson


    【解决方案1】:

    您可以使用 Newtonsoft 的 BsonDataWriterJObject 写入 BSON 流,如下所示:

    var json = "{\"name\":\"value\"}";
    var jObject = JObject.Parse(json);
    
    using var stream = new MemoryStream(); // Or open a FileStream if you prefer
    using (var writer = new BsonDataWriter(stream) { CloseOutput = false })
    {
        jObject.WriteTo(writer);
    }
    // Reset the stream position to 0 if you are going to immediately re-read it.
    stream.Position = 0;
    

    然后,您可以使用 MongoDB .NET 驱动程序解析写入的流,如下所示:

    // Parse the BSON using the MongoDB driver
    BsonDocument bsonData;
    using (var reader = new BsonBinaryReader(stream))
    {
        var context = BsonDeserializationContext.CreateRoot(reader);
        bsonData = BsonDocumentSerializer.Instance.Deserialize(context);            
    }
    

    然后像这样检查创建的文档的有效性:

    // Verify that the BsonDocument is semantically identical to the original JSON.
    // Write it to JSON using the MongoDB driver
    var newJson = bsonData.ToJson();
    
    Console.WriteLine(newJson); // Prints { "name" : "value" }
    
    // And assert that the old and new JSON are semantically identical
    Assert.IsTrue(JToken.DeepEquals(JToken.Parse(json), JToken.Parse(newJson))); // Passes
    

    注意事项:

    • 当您执行var bsonData = writer.ToBsonDocument(); 时,您实际上是在使用 MongoDB 扩展方法 BsonExtensionMethods.ToBsonDocument() 序列化 Newtonsoft 的 BsonDataWriter,这解释了您的测试代码中 bsonData 文档的奇怪内容。

      相反,序列化的 BSON 可以从它刚刚写入的流中获取。

    • 如果您要立即重新读取流,可以通过设置JsonWriter.CloseOutput = false 使其保持打开状态。写入后设置流位置为0

    • 虽然您的方法避免了序列化和解析 JSON 字符串的开销,但您仍在序列化和反序列化 BSON 二进制流。

    演示小提琴here.

    【讨论】:

      【解决方案2】:

      如果你已经有了 json 字符串,你可以简单地用它创建一个 bson 文档

      var document= BsonDocument.Parse("{\"name\":\"value\"}");
      

      如果你严格来说有一个JObject,你可以序列化这个JObject,然后将结果解析成一个BSONDocument

      var document = BsonDocument.Parse(Newtonsoft.Json.JsonConvert.SerializeObject(jObject));
      

      【讨论】:

      • 我有一个JObject,想直接转成BSONDocument(避免序列化成字符串和字符串解析)
      【解决方案3】:

      Accepted answer 避免序列化为字符串,而是序列化为二进制,然后立即反序列化。 以下映射JObject 直接遍历BsonDocument

      public static BsonDocument ToBsonDocument(this JObject o) =>
          new(o.Properties().Select(p => new BsonElement(p.Name, p.Value.ToBsonValue())));
      
      public static BsonValue ToBsonValue(this JToken t) =>
          t switch
          {
              JObject o => o.ToBsonDocument(),
              JArray a => new BsonArray(a.Select(ToBsonValue)),
              JValue v => BsonValue.Create(v.Value),
              _ => throw new NotSupportedException($"ToBsonValue: {t}")
          };
      

      【讨论】:

        猜你喜欢
        • 2014-08-25
        • 1970-01-01
        • 2013-09-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-21
        • 1970-01-01
        相关资源
        最近更新 更多