将 Newtosoft JObject 直接转换为 BsonDocument
Convert Newtosoft JObject directly to BsonDocument
尝试使用此示例 https://www.newtonsoft.com/json/help/html/WriteJTokenToBson.htm 将 JObject
转换为 BsonDocument
(BsonWriter
已过时,因此我使用 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 的 BsonDataWriter
将 JObject
写入 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}")
};
尝试使用此示例 https://www.newtonsoft.com/json/help/html/WriteJTokenToBson.htm 将 JObject
转换为 BsonDocument
(BsonWriter
已过时,因此我使用 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 的 BsonDataWriter
将 JObject
写入 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}")
};