使用C#将嵌套文档插入MongoDB

4
我试图使用C#向MongoDB中插入嵌套文档。我有一个名为categories的集合,该集合必须存在两个数组的文档,一个名为categories,另一个名为standards。这些数组内部必须存在新的文档,其具有自己的ID,并包含上述相同名称的数组。以下是我目前拥有的内容,但我不确定如何继续进行。如果您查看代码,我想要做的是在categories文档中将“namingConventions”文档嵌套添加到categories数组下面,但是namingConventions也必须具有唯一的ID。
目前我不确定是否以最佳方式完成了所有这些工作,因此我欢迎任何有关整个过程的建议。
namespace ClassLibrary1
{
using MongoDB.Bson;
using MongoDB.Driver;
public class Class1
{
       public void test()
        {
            string connectionString = "mongodb://localhost";
            MongoServer server = MongoServer.Create(connectionString);
            MongoDatabase standards = server.GetDatabase("Standards");
            MongoCollection<BsonDocument> categories = standards.GetCollection<BsonDocument>("catagories");

            BsonDocument[] batch = {
                                       new BsonDocument { { "categories", new BsonArray {} },
                                                        { "standards", new BsonArray { } }  },
                                       new BsonDocument { { "catagories", new BsonArray { } },
                                                        { "standards", new BsonArray { } }  },
                                   };
            categories.InsertBatch(batch);

            ((BsonArray)batch[0]["categories"]).Add(batch[1]);
            categories.Save(batch[0]);           
        }
    }
}

为了清晰明确,这是我需要的:

我正在建立一个编码标准网站。公司希望将所有标准以树形结构存储在MongoDB中。每个标准都必须有一个唯一的ID,以便除了可以作为树形结构查询外,还可以单独查询。例如:

/* 0 */
{
  "_id" : ObjectId("4fb39795b74861183c713807"),
  "catagories" : [],
  "standards" : []
}

/* 1 */
{
  "_id" : ObjectId("4fb39795b74861183c713806"),
  "categories" : [{
      "_id" : ObjectId("4fb39795b74861183c713807"),
      "catagories" : [],
      "standards" : []
    }],
  "standards" : []
}

现在我已经编写了代码来实现这一点,但问题似乎在于当我将对象“0”添加到对象“1”的类别数组中时,它并没有建立引用,而是复制了它。这是不可行的,因为如果进行更改,它们将对原始对象“0”进行更改,因此它们不会被推送到类别数组中正在进行的副本中,至少这就是发生在我身上的情况。希望这能澄清我所寻求的内容。


“0”文档的ID是否故意与“1”文档的第一个类别ID相同? - Craig Wilson
我现在明白了。这不会自动发生。在MongoDB中,复制是实现此行为的唯一方法。坦率地说,在任何数据库中,这种行为都不会自动发生。您需要它变成这样的原因吗?对我来说,这个模式真的没有意义。 - Craig Wilson
好的,那我们放弃这个想法。我该如何创建文档的引用呢?根据MongoDB文档,这是可能的,但我不知道如何在C#中实现它,文档只是简单地说要使用DBRef,问题是我不知道怎么做。 - John
当你说在顶层实时运行时,是指为每个标准创建一个新文档吗? - John
我强烈建议你不要使用DBRefs。它们不是约束(就像在SQL中一样),而且它们仅仅占用比简单存储引用ID更多的空间。但是,我不知道为什么你需要在模式中使用“引用”。 - Craig Wilson
显示剩余6条评论
4个回答

7
所以,根据您最新的评论,看起来这才是您真正想要的结构:
{
    _id: ObjectId(),

    name: "NamingConventions",

    categories: [
        {
            id: ObjectId(),
            name: "Namespaces",
            standards: [
                {
                    id: ObjectId(),
                    name: "TitleCased",
                    description: "Namespaces must be Title Cased."
                },
                {
                    id: ObjectId().
                    name: "NoAbbreviations",
                    description: "Namespaces must not use abbreviations."
                }
            ]
        },
        {
            id: ObjectId(),
            name: "Variables",
            standards: [
                {
                    id: ObjectId(),
                    name: "CamelCased",
                    description: "variables must be camel cased."
                }
            ]
        }
    ]
}

假设这是正确的,那么下面是如何插入其中之一的方法:

var collection = db.GetCollection("some collection name");

var root = new BsonDocument();
root.Add("name", "NamingConventions");
var rootCategories = new BsonArray();
rootCategories.Add(new BsonDocument
{
   { "id": ObjectId.GenerateNewId() },
   { "name", "Namespaces" },
   { "standards", new BsonArray() }
});

root.Add("categories", rootCategories);
//etc...
collection.Save(root);

希望这能有所帮助,如果没有的话,我就放弃了 :).

这正是我想要实现的,但你发布的代码并没有做到这一点。我进行了更改以使其执行,但它只给我生成了两个没有任何链接的文档。 - John
更新了示例以更加全面。您必须将字段添加到文档中以使它们持久化。 - Craig Wilson
搞定了!非常感谢您一直陪伴着我。我只需要微调一下代码就可以了。{"id": ObjectId.NewObjectId()}并不起作用,必须改成{ "_id", ObjectId.GenerateNewId()}。 - John

1

所以,我猜你的问题让我有些困惑。如果你只是想将namingConventions文档存储在数组中,那么你不需要为它们创建一个集合。相反,只需将它们添加到bson数组中并进行存储即可。

var categoriesCollection = db.GetCollection<BsonDocument>("categories");

var category = new BsonDocument();
var namingConventions = new BsonArray();
namingConventions.Add(new BsonDocument("convention1", "value"));

category.Add("naming_conventions", namingConventions);

categoriesCollection.Insert(category);

这将为一个类别创建一个新文档,在其中创建一个名为naming_conventions的数组,并在其中创建一个单独的文档,其中包含一个名为“convention1”的元素和一个值为“value”的元素。


我看到了,但是上面的内容为什么不回答你的问题呢?关于唯一标识符,只需使用 GUID,在创建文档时,使用 Guid.New() 为其 id 字段分配一个值即可。 - Craig Wilson
因为这不会在数组中创建对文档的引用。如果我对文档进行更改,数组仍然保持不变,更不用说没有ID了。至于使用Guid.New(),你需要更具体一些,我不知道你在说什么。 - John
我不确定我们能否在这里帮助您,因为您的问题非常模糊,我们很难理解您的需求。您也在mongodb组中问了同样的问题。最好只使用一个地方。Guid.NewGuid() => http://msdn.microsoft.com/en-us/library/system.guid.newguid.aspx - Craig Wilson
我相信我已经回答了这个问题。也许我需要暂时离开,因为显然我漏掉了什么。我会让同事看一下这个问题和答案。 - Craig Wilson

0
var filter = Builders<CollectionDefination>.Filter.Where(r => r._id== id);
var data = Builders<CollectionDefination>.Update.Push(f=> 
    f.categories,categoriesObject);
await _dbService.collection.UpdateOneAsync( filter,data);

注意:确保嵌入式文档类型[Categories]是数组。

0
我也不太确定你想要实现什么。如果你能发布一些JSON格式的样本文档,我们就可以向你展示如何编写与之匹配的C#代码。
或者,如果你想讨论你的模式,最好在JSON的上下文中进行,而不是在C#中。一旦确定了模式,我们就可以讨论如何在C#中编写符合该模式的文档。
你原始描述中听起来不对的一件事是“该集合中必须存在2个数组”。一个集合只能包含文档,而不能包含数组。如果你想要,文档本身可以包含数组。

抱歉,我是指文档,以下是我需要的JSON格式:请参见原帖进行编辑。 - John

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接