Mongo c#驱动程序:反序列化BsonValue

本文关键字:反序列化 BsonValue 驱动程序 Mongo | 更新日期: 2023-09-27 18:02:03

我在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; }
}

我以这种方式选择"Product A"文档:

MongoServer srv = MongoServer.Create(myConnStr);
BsonDocument doc = srv["db"]["products"].FindOneById(ObjectId.Parse("abcdef01234"));
BsonValue dimensionsVal = doc["Dimensions"];

现在我有一个名为dimensionsVal的BsonValue,它的类型是BsonArray。我真正想要的是一个List我如何将dimensionsVal转换为List?

编辑维度类实际上比我所描述的要复杂得多。由于内存问题,我希望将Dimensions与Product分开。我希望将Product保存在内存中,而不是(可能非常庞大的)维度列表。由于这个原因,我不想把List作为Product类的属性。

Mongo c#驱动程序:反序列化BsonValue

可以这样做:

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());

更新:

你可能在寻找包含/排除功能。在c#驱动程序中是这样做的:

 // load products without array of Dimensions
MongoCursorInstance.SetFields(Fields.Exclude("Dimensions"));
//load empty product with Dimensions and _id
MongoCursorInstance.SetFields(Fields.Include("Dimensions"));

为什么不直接为product创建类呢?在这种情况下,驱动程序将能够自动反序列化数据:

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);
}

试试这个:

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"));

产品。尺寸现在将包含您需要的List<>

我将使用类型为List的Dimensions属性声明您的类,就像其他人建议的那样。然后,如果您想要读取没有尺寸值的Product ,请这样写:

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要有效得多。这种方法会导致数据的两个副本被加载到内存中(尽管如果不保留对BsonDocument的引用,可能会在此后不久被垃圾收集)。