Драйвер Mongo С#: Deserialize BsonValue
У меня есть документ в mongodb, который подобен этому:
{
"_id": "abcdef01234",
"Name": "Product A",
"Dimensions": [
{
"Height": 32,
"Width": 64
},
{
"Height": 16,
"Width": 32
},
{
"Height": 8,
"Width": 16
}
]
}
У меня также есть класс, определенный для представления измерений (вспомогательный документ сверху)
public class Dimension
{
public int Height { get; set; }
public int Width { get; set; }
}
Я выбираю документ "Продукт А" таким образом:
MongoServer srv = MongoServer.Create(myConnStr);
BsonDocument doc = srv["db"]["products"].FindOneById(ObjectId.Parse("abcdef01234"));
BsonValue dimensionsVal = doc["Dimensions"];
Теперь у меня есть BsonValue с именем dimensionVal, который имеет тип BsonArray. Я действительно хочу, это List <Dimension> . Как преобразовать размерыVal в List <Dimension> ?
Edit
Класс измерения на самом деле значительно сложнее, чем то, что я описал. Я хочу сохранить размеры отдельно от продукта из-за проблем с памятью. Я хочу сохранить Продукт в памяти, но не (потенциально огромный) список измерений. По этой причине я не хочу иметь список как свойство класса Product.
Ответы
Ответ 1
Вот как это можно сделать:
using MongoDB.Bson.Serialization;
MongoServer srv = MongoServer.Create(myConnStr);
BsonDocument doc = srv["db"]["products"].FindOneById(ObjectId.Parse("abcdef01234"));
BsonValue dimVal = doc["Dimensions"];
List<Dimension> d = BsonSerializer.Deserialize<List<Dimension>>(dimVal.ToJson());
Ответ 2
Попробуйте следующее:
public class Product
{
[BsonId]
public ObjectId Id { get; set; }
public string Name{ get; set; }
public List<DimensionDoc> Dimensions{ get; set; }
}
public class DimensionDoc
{
public int Height { get; set; }
public int Width { get; set; }
}
Product product = srv["db"]["products"].FindOneByIdAs<Product>(ObjectId.Parse("abcdef01234"));
product.Dimensions теперь будет содержать список < > , который вам нужен.
Ответ 3
Update:
Вероятно, вы ищете include/exclude. В драйвере С# это делается так:
// load products without array of Dimensions
MongoCursorInstance.SetFields(Fields.Exclude("Dimensions"));
//load empty product with Dimensions and _id
MongoCursorInstance.SetFields(Fields.Include("Dimensions"));
Почему бы просто не создать класс для продукта? В этом случае драйвер сможет автоматически десериализовать данные:
class Product
{
[BsonId]
public ObjectId Id { get; set; }
public string Name{ get; set; }
public List<Dimension> Dimensions{ get; set; }
}
var product = srv["db"]["products"].FindOneByIdAs<Product>();
var dimentions = product.Dimensions;
Но если вы не хотите создавать класс Product
, вы можете пойти следующим образом:
BsonArray dimensionsVal = doc["Dimensions"].AsBsonArray;
var list = new List<Dimension>();
foreach (BsonValue value in dimensionsVal)
{
var bsonDoc = (BsonDocument) value;
var d = new Dimension();
d.Height = bsonDoc["Height"];
d.Width = bsonDoc["Width"];
list.Add(d);
}
Ответ 4
Я объявляю ваш класс с свойством Dimensions типа List <Dimension> , как предлагали другие. Затем, если вы хотите прочитать Product без значений Dimensions, напишите это:
ObjectId productId;
var query = Query.EQ("_id", productId);
var fields = Fields.Exclude("Dimensions");
var product = collection.Find(query).SetFields(fields).FirstOrDefault();
// product.Dimensions will be null because there was no data for it
и если вы хотите прочитать полный продукт, включая все размеры, напишите это:
ObjectId productId;
var query = Query.EQ("_id", productId);
var product = collection.FindOne(query);
// product.Dimensions will be populated this time
Это будет намного эффективнее, чем чтение Dimensions в BsonDocument и преобразование их в List <Dimension> с помощью написанного вручную кода. Этот подход приводит к получению двух копий данных, загружаемых в память (хотя предположительно версия BsonDocument будет собираться с мусором вскоре после этого, если вы не сохраните ссылку на нее).