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

发布于 2024-11-24 03:21:33 字数 926 浏览 0 评论 0原文

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

我以这种方式选择“产品 A”文档:

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

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

编辑 维度类实际上比我所描述的要复杂得多。出于内存问题,我想将尺寸与产品分开。我想将产品保留在内存中,而不是(可能巨大的)维度列表。因此,我不想将 List 作为 Product 类的属性。

I have a document in mongodb that is structured similar to this:

{
  "_id": "abcdef01234",
  "Name": "Product A",
  "Dimensions": [
    {
      "Height": 32,
      "Width": 64
    },
    {
      "Height": 16,
      "Width": 32
    },
    {
      "Height": 8,
      "Width": 16
    }
  ]
}

I also have a class defined to represent dimensions (the sub document from above)

public class Dimension
{
  public int Height { get; set; }
  public int Width { get; set; }
}

I am selecting the "Product A" document in this manner:

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

Now I have a BsonValue named dimensionsVal which is of type BsonArray. What I really want is a List<Dimension>. How do I convert dimensionsVal to a List<Dimension>?

Edit
The dimension class is actually significantly more complex than what I described. I want to keep the Dimensions separate from the Product because of memory concerns. I want to keep the Product in memory, but not the (potentially enormous) list of dimensions. For this reason, I don't want to have a List as a property of the Product class.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

夏花。依旧 2024-12-01 03:21:33

具体方法如下:

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

Here is how it can be done:

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());
我纯我任性 2024-12-01 03:21:33

更新:

您可能正在寻找include/排除功能。在 C# 驱动程序中,它是这样做的:

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

Update:

You probably looking for include/exclude functionality. In c# driver it done so:

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

Why not just create class for product? In this case driver will be able to deserialize data automatically :

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;

But if you don't want create Product class you can go this way:

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);
}
慵挽 2024-12-01 03:21:33

试试这个:

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 现在将包含 List<>你需要。

Try this:

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 will now contain the List<> you need.

咆哮 2024-12-01 03:21:33

我将使用 List类型的 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更有效手写代码。这种方法会导致数据的两个副本加载到内存中(尽管如果您不保留对它的引用,BsonDocument 版本可能很快就会被垃圾收集)。

I would declare your class with a Dimensions property of type List<Dimension> as others have proposed. Then if you want to read a Product without the Dimensions values write this:

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

and when you want to read the full product including all of the Dimensions write this:

ObjectId productId;
var query = Query.EQ("_id", productId);
var product = collection.FindOne(query);
// product.Dimensions will be populated this time

This will be much more efficient than reading the Dimensions into a BsonDocument and converting them to a List<Dimension> with hand-written code. That approach results in two copies of the data being loaded in memory (although presumably the BsonDocument version will be garbage collected soon thereafter if you don't keep a reference to it).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文