猿教程 Logo

.Net连接MongoDb:插入文档

介绍

在上一篇文章中,我们在Windows上成功安装了最新版本的MongoDb。 我想你会同意这是一个非常简单和无痛的过程。 我们开始探索MongoDb安装文件夹中最重要的两个工具。 Mongo.exe启动可以使用命令和查询与数据库进行连接的客户机。 Mongod.exe依次启动数据库。 我们看到了一些命令和查询示例,例如插入新记录,搜索一个并且还删除一个。 MongoDb的默认查询语言是JavaScript,查询函数的大多数参数都将是JSON。 一个JSON查询参数其实也是一个文档。

在这篇文章中,我们将进一步了解插入。 如果您想自己尝试这些示例,请不要忘记在两个单独的命令提示符中启动mongo.exe和mongod.exe。

插入文档

插入文档大致对应于标准SQL中的INSERT语句。 我们已经看到在上一篇文章中插入的例子,并没有任何魔术。 我们调用JavaScript命令“db.[collectionName] .insert([some valid JSON])”,就是这样。 我们传递的JSON是添加到集合中的文档。 我们现在知道,一个集合可以是一组不同的JSON文件。 因此,很难在关系数据库中找到集合的确切对应,但是表是可接受的答案。 一个表中的每个记录大致对应一个文档。

“db”关键字将自动将请求路由到当前选择的数据库,因此我们不需要在JavaScript命令中提供数据库名称。 这类似于写作例如 “USE [databaseName]”在SQL之后,每个语句将针对该数据库执行,除非被覆盖。

这是一个要求,MongoDb集合中的所有文档都有一个唯一的ID,它也将作为主键和不可变键。 这是不可变的,因为一旦我们将它设置为一个不能被更新的文档。 默认情况下,ID字段称为“_id”。 如果您没有提供任何值,那么MongoDb将自动为其分配一个ObjectId类型的ID。 ObjectId是BSON规范的一部分。 MongoDb在此页面上提供了有关此类型的更多详细信息。 实质上,ObjectId具有与GUID相同的功能,即全局唯一的标识符。

我们来试试我们是否提供自己的ID。 我在一个mongo客户端shell中执行以下命令。 每行后按Enter键:

use loadtest
db.products.insert({"_id" : 1, "name" : "radio", "stock_level" : 100})

服务器响应...

WriteResult({ "nInserted" : 1 })

...即。 一个文件被插入到产品集合中。

接下来我将尝试添加一个具有相同ID的产品:

db.products.insert({"_id" : 1, "name" : "tv", "stock_level" : 50})

我们从数据库获取一个大的NOPE:

WriteResult({
        "nInserted" : 0,
        "writeError" : {
                "code" : 11000,
                "errmsg" : "E11000 duplicate key error collection: loadtest.products index: _id_ dup key: { : 1.0 }"
        }
})

“duplicate key error”“重复键错误”告诉我们究竟出了什么问题。

该示例还显示,MongoDb中的文档没有自动递增的整数ID,至少在MS SQL中没有什么可用的。 如果你想实现类似的东西,那么你需要在.NET逻辑中实现它。 请注意,获取收集中的文档数量并将其递增一个是由于多线程而导致的风险策略。 假设您运行第一个查询的时间是20,即“选择产品集合中的文档数量”。 然后另一位用户在您之前添加一个产品,您都将提供相同的ID,即21.任何一个客户端都将获得上述异常。 然后,您可以继续增加ID字段,直到您的查询成功,但这不是一种非常“现代”的方法。 如果您作为读者已经找到了一个很好的解决方案,那么欢迎您在评论部分介绍。

另一个流行的标识符类型是GUID或UUID,如下所示:

434b1534-fc4d-47aa-9406-6d48cae713d6 

f847a7d8-5e7f-41d7-a01b-85ee3f2776e8 

f96589ff-cac7-4fe0-a486-12c7697de069

这些由MS SQL中的“uniqueidentifier”类型表示。 事实证明,在MongoDb中,GUID不容易使用,最好以字符串方式存储。 这是StackOverflow上的线程,用于描述问题:

“使用GUID有一些陷阱,主要涉及如何使用mongo shell中的二进制表示形式,以及导致使用不同字节顺序存储GUID的不同驱动程序的历史事故。

MongoDb JavaScript中没有本地的GUID生成器函数,所以我们不能在C#中输入类似“Guid.NewGuid()”的内容。 MongoDb有一个UUID功能,但它需要一个输入字符串。

无论如何,我们来看看我们是否可以插入一个字符串GUID的对象:

db.products.insert({"_id" : "434b1534-fc4d-47aa-9406-6d48cae713d6", "name" : "tv", "stock_level" : 50})

相关实例:

WriteResult({ "nInserted" : 1 })

我们来试试另一个:

db.products.insert({"_id" : "f96589ff-cac7-4fe0-a486-12c7697de069", "name" : "computer", "stock_level" : 80})

是的,这似乎工作正常。

上述SO线程说明以下关于存储为字符串的GUID:

“至于将GUID存储为字符串,这并不是一件没有事情要做的事情,它确实让查看和查询mongo shell中的数据更容易,避免了不同字节顺序的所有问题。 唯一的缺点是它使用更多的空间(大约两倍)。“

因此,我们可以得出结论,至少有一个可行的解决方法。

也可以在我们自己的C#模型中采用MongoDb ID风格。 在所有的ObjectId都是一个全球唯一的标识符之后,就像上面提到的3个GUID一样,它们只是看起来不一样,并且是从其他输入生成的,例如当前时间(以毫秒为单位)。 但是,它有自己的缺点。 我现在不想去那条轨道。 当我们开始编写一些C#代码时,我们稍后再回到ID的主题。 域对象的ID是其最重要的属性,一些开发人员倾向于忽略它。 那么当然不是你和我,而是那些其他非常粗心的开发者呢?

长度限制

我们之前说过,我们可以轻松地插入代表我们对象关系的JSON文档。 例如。 订单有OrderItems,作者有图书,汽车有轮胎等。这些依赖对象可以保存为同一个JSON中的内联文档,例如数组。 从本网站获取的菜单项示例:

{"menu": {
  "id": "file",
  "value": "File",
  "popup": {
    "menuitem": [
      {"value": "New", "onclick": "CreateNewDoc()"},
      {"value": "Open", "onclick": "OpenDoc()"},
      {"value": "Close", "onclick": "CloseDoc()"}
    ]
  }
}}

菜单项是排列在数组中的菜单的子文档。 这是一个非常小的文档,但是现实生活中的文档可以通过这种方式变得非常大。 想象一下,试图将亚马逊的所有客户都放在这样的单一阵列中。 目前MongoDb中单个文档的最大大小为16MB。 这是一个单一的文件,但亚马逊将填补一个纳秒。

这是设计文档时需要考虑的另外一个考虑因素。 我们应该将相关对象嵌入同一个“母亲”文档吗? 一般的指导原则是,如果您想要轻松访问依赖对象并进行更新,然后将它们放在单独的集合中,即单独的文档中。 很可能您需要访问和更新订单的订单行,即您需要订单集合和OrderLine集合,并通过某些辅助键将订单行连接到订单。 或者,您可以将订单行的ID存储在订单的数组中,并在其中创建连接。 在MongoDb中没有像“级联删除”,以确保没有孤儿,因此您需要在客户端代码中实现任何相关的更新和删除。

稍后我们再回到这个话题, 正如你所看到的,NoSql是一个令人兴奋的技术,但显然并不是所有的东西都在这个世界是玫瑰色和无痛的。

在下一篇文章中,我们将开始研究查询。


版权声明:本站所有教程均为本站原创或翻译,转载请注明出处,请尊重他人劳动果实。请记住本站地址:www.yuanjiaocheng.net (猿教程) 作者:卿文刚
本文标题: C#环境
本文地址:http://www.yuanjiaocheng.net/CsharpMongo/3.html