MongoDB C#ドライバーを使用しています。 MongoDB固有の型(ObjectIDやISODateなど)を含むデータを含むBsonDocument
があります。これを有効な汎用JSON文字列に変換したいと思います。言い換えれば、_id: ObjectId(...)
やdate: ISODate(...)
のようなものは使用できませんが、__id: "..."
_と_date: "..."
_を優先します。基本的に、MongoDBだけが認識するこれらの特殊な型を通常の文字列に変換して、より簡単に解析できるようにしたいと考えています。問題は、.ToJson()
などの組み込み関数(別のStackOverflowの回答が示唆している)では、これらの特別な型を維持しているため、ドキュメントを実際に有効なJSONに変換しないことです。私のドキュメントには多くのレベルの配列とサブドキュメントも含まれているため、単純なforループでは不十分です。この問題を回避するBsonDocument
を変換する最良の方法は何ですか?すべての問題を修正するために、手動でドキュメントを再帰するのではなく、組み込みのものを使用します。
私は同じことに遭遇しました、あなたは有効なJSONを次のようにして得ることができます:
var jsonWriterSettings = new JsonWriterSettings { OutputMode = JsonOutputMode.Strict };
JObject json = JObject.Parse(postBsonDoc.ToJson<MongoDB.Bson.BsonDocument>(jsonWriterSettings));
ただし、次のような結果が返されます。
{"_id":{"$oid":"559843798f9e1d0fe895c831"}, "DatePosted":{"$date":1436107641138}}
私はまだそれを平坦化する方法を見つけようとしています。
ほとんどの場合これを使用します Json.NET
JsonConvert.SerializeObject(obj);
ほとんどの場合、それはトリックを行います。必要に応じて、いくつかを設定できますJsonSerializerSettings
私の意見では、最良のオプションはNewtonsoft.Json.Bson.BsonReader
。ここに完全な例があります:
public string ToJson(BsonDocument bson)
{
using (var stream = new MemoryStream())
{
using (var writer = new BsonBinaryWriter(stream))
{
BsonSerializer.Serialize(writer, typeof(BsonDocument), bson);
}
stream.Seek(0, SeekOrigin.Begin);
using (var reader = new Newtonsoft.Json.Bson.BsonReader(stream))
{
var sb = new StringBuilder();
var sw = new StringWriter(sb);
using (var jWriter = new JsonTextWriter(sw))
{
jWriter.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
jWriter.WriteToken(reader);
}
return sb.ToString();
}
}
}
私はこれがすべてのケースを正しく処理するはずだと思います(日付、ID、...)。
Mongodb _idエントリをスキップする方法は次のとおりです。
var collection = _database.GetCollection<BsonDocument>("test");
var result = await collection.Find(new BsonDocument())
.Project(Builders<BsonDocument>.Projection.Exclude("_id"))
.ToListAsync();
var obj = result.ToJson();
どうですか
String json = result.toJson(JsonWriterSettings.builder().objectIdConverter(new Converter<ObjectId>() {
@Override
public void convert(ObjectId value, StrictJsonWriter writer) {
writer.writeString(value.toHexString());
}
}).build());
BSONドキュメントのコンテンツが次のように保存されている場合
{
"Date" : "2019-04-05T07:07:31.979Z",
"BSONCONTENT" : {
"_t" : "MongoDB.Bson.BsonDocument, MongoDB.Bson",
"_v" : {
"A" : "XXXX",
"B" : 234
}
}
}
次に、ジェネリッククラスで動作します。
private static T ProcessBsonConversion<T>(BsonDocument data)
{
var content = data.GetElement("_v");
var jsonDataContent= content.Value.AsBsonValue.ToJson();
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(jsonDataContent);
}
私の問題は、DotNet Core WebAPIがオブジェクトをjsonにシリアル化する方法に関係していました。 jsonとしてフォーマットされたメソッドから文字列を返す場合、WEBAPIはそれを再びjsonにシリアル化します。これは、MongoDbに保存する一般的なBsonDocumentを使用している場合にのみ必要です。
[HttpGet()]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<string>> GetAsync()
{
return Ok(ret.ToJson());
}
修正
[HttpGet()]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<object>> GetAsync()
{
var doc = await _collection.Find(...).FirstOrDefaultAsync();
return Ok(JObject.Parse(doc.ToJson()));
}
動的データを追加できるようにBsonDocumentを持つモデルを返す場合にこのASP.NET Coreを使用する必要がある場合。 MarkKGreenwayの回答に基づいて、このJsonConverter実装を使用できます。
public class BsonDocumentJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(BsonDocument);
}
public override bool CanRead
{
get
{
return false;
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
//string json = (value as BsonDocument).ToJson(); //!NB: this returns BSON not JSON. Why on earth is it called ToJson!?
string json = JsonConvert.SerializeObject(value);
writer.WriteRawValue(json);
}
}
次に、Startup.cs
以下を追加するだけです。
services.AddMvc()
.AddJsonOptions(options => options.SerializerSettings.Converters.Add(new BsonDocumentJsonConverter()));