将 Newtosoft JObject 直接转换为 BsonDocument

Convert Newtosoft JObject directly to BsonDocument

尝试使用此示例 https://www.newtonsoft.com/json/help/html/WriteJTokenToBson.htmJObject 转换为 BsonDocumentBsonWriter 已过时,因此我使用 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,避免序列化为字符串和字符串解析

如果您已经有了 json 字符串,您可以简单地从中创建一个 bson 文档

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

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

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

您可以使用 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()[=48] 序列化 Newtonsoft 的 BsonDataWriter =],解释了你的测试代码中bsonData文档的奇怪内容

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

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

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

演示 fiddle here.

避免序列化为字符串,而是序列化为二进制文件,而只是为了随后立即反序列化它。 以下映射 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}")
    };