mongodb指南(翻译)(四) developer zone 教程

运行mongodb

请参与快速启动指南来启动mongodb。

连接到数据库

首先使用数据库shell程序来操作数据库。(我们同样可以使用任何语言的驱动来做类似的操作。shell程序可以很方便的进行交互和管理。)

这样启动mongodb JavaScript shell:

  1. # 'mongo' is shell binary. exact location might vary depending on  
  2. # installation method and platform  
  3. $ bin/mongo  


默认情况下shell程序会连接到本地的数据库“test”。你将看到:

  1. MongoDB shell version: <whatever>  
  2. url: test  
  3. connecting to: test  
  4. type "help" for help  
  5. >  


"connecting to:"告诉你目前正在使用的数据库名称。可以这样切换数据库:

  1. > use mydb  
  2. switched to db mydb  


切换数据库的use命令并不会立即创建这个数据库-数据库延迟到数据第一次插入的时候创建。这意味着如果你use某个数据库,但是show dbs命令并不会将它列出来除非有数据插入。

要想查看可以使用的命令列表,可以敲入help.

动态模式(模式自由)

MongoDB像传统的RDBMS一样拥有数据库、集合和索引。在一些场合(数据库和集合)这些对象可以被隐式创建,不过一旦创建它们就存在于一个系统目录中(db.systems.collections, db.system.indexes)。

集合中包含了(BSON)文档。在这些文档中是一些域。在mongodb中没有预定义的域(对应于RDBMS中的列)。对于文档内的域没有任何模式 要求-这些域和他们的值类型可以是任何类型。在这里增加一列也没有“alter table”的概念。尽管没有这样一个要求,但实际应用中,在一个集合中的文档拥有相类似的结构是非常普遍的。这种灵活性意味着模式迁移和增大在实际中非 常容易-很少会需要你去写脚本做类似于“alter table”的操作。除了让模式迁移灵活外,这种便利使得在数据库之上做迭代开发更加容易。


向集合中插入数据

我们首先创建一个集合然后向里面插入一些数据。我们会创建两个对象,j和t,然后将他们保存在集合thins中。

在接下来的例子中,">"代表shell中输入命令的提示符。

  1. > j = { name : "mongo" };  
  2. {"name" : "mongo"}  
  3. > t = { x : 3 };  
  4. { "x" : 3 }  
  5. > db.things.save(j);  
  6. > db.things.save(t);  
  7. > db.things.find();  
  8. { "_id" : ObjectId("4c2209f9f3924d31102bd84a"), "name" : "mongo" }  
  9. { "_id" : ObjectId("4c2209fef3924d31102bd84b"), "x" : 3 }  
  10. >  


有几点需要注明:

  • 我们没有预先创建这个集合。在我们首次插入数据时数据库自动创建了它。
  • 保存的文档可以拥有不同的结构-实际上在这个例子中,这两个文档根本没有任何相同的数据元素。在实际应用中,在一个集合中保存的数据通常具有相同的结构。
  • 在插入到数据库之前,对象的域_id被赋予了一个object ID(如果还没有这个域).
  • 当你运行上面的例子时,你的ObjectID值可能会不同。

让我们增加更多的记录到该集合中:

  1. > for (var i = 1; i <= 20; i++) db.things.save({x : 4, j : i});  
  2. > db.things.find();  
  3. { "_id" : ObjectId("4c2209f9f3924d31102bd84a"), "name" : "mongo" }  
  4. { "_id" : ObjectId("4c2209fef3924d31102bd84b"), "x" : 3 }  
  5. { "_id" : ObjectId("4c220a42f3924d31102bd856"), "x" : 4, "j" : 1 }  
  6. { "_id" : ObjectId("4c220a42f3924d31102bd857"), "x" : 4, "j" : 2 }  
  7. { "_id" : ObjectId("4c220a42f3924d31102bd858"), "x" : 4, "j" : 3 }  
  8. { "_id" : ObjectId("4c220a42f3924d31102bd859"), "x" : 4, "j" : 4 }  
  9. { "_id" : ObjectId("4c220a42f3924d31102bd85a"), "x" : 4, "j" : 5 }  
  10. { "_id" : ObjectId("4c220a42f3924d31102bd85b"), "x" : 4, "j" : 6 }  
  11. { "_id" : ObjectId("4c220a42f3924d31102bd85c"), "x" : 4, "j" : 7 }  
  12. { "_id" : ObjectId("4c220a42f3924d31102bd85d"), "x" : 4, "j" : 8 }  
  13. { "_id" : ObjectId("4c220a42f3924d31102bd85e"), "x" : 4, "j" : 9 }  
  14. { "_id" : ObjectId("4c220a42f3924d31102bd85f"), "x" : 4, "j" : 10 }  
  15. { "_id" : ObjectId("4c220a42f3924d31102bd860"), "x" : 4, "j" : 11 }  
  16. { "_id" : ObjectId("4c220a42f3924d31102bd861"), "x" : 4, "j" : 12 }  
  17. { "_id" : ObjectId("4c220a42f3924d31102bd862"), "x" : 4, "j" : 13 }  
  18. { "_id" : ObjectId("4c220a42f3924d31102bd863"), "x" : 4, "j" : 14 }  
  19. { "_id" : ObjectId("4c220a42f3924d31102bd864"), "x" : 4, "j" : 15 }  
  20. { "_id" : ObjectId("4c220a42f3924d31102bd865"), "x" : 4, "j" : 16 }  
  21. { "_id" : ObjectId("4c220a42f3924d31102bd866"), "x" : 4, "j" : 17 }  
  22. { "_id" : ObjectId("4c220a42f3924d31102bd867"), "x" : 4, "j" : 18 }  
  23. has more  


注意并不是所有的文档都会显示出来-当自动迭代一个游标时,shell将返回数目限制在20.由于我们已经在集合中插入了2个文档,因此我们只看到了18个新插入的文档。

如果我们想要返回下一组结果,可以使用快捷方式it。接着上面的代码:

  1. { "_id" : ObjectId("4c220a42f3924d31102bd866"), "x" : 4, "j" : 17 }  
  2. { "_id" : ObjectId("4c220a42f3924d31102bd867"), "x" : 4, "j" : 18 }  
  3. has more  
  4. > it  
  5. { "_id" : ObjectId("4c220a42f3924d31102bd868"), "x" : 4, "j" : 19 }  
  6. { "_id" : ObjectId("4c220a42f3924d31102bd869"), "x" : 4, "j" : 20 }  


技术上,find()返回一个游标对象。但在上面的实例中,我们并没有将这个游标赋值到一个变量。因此,shell自动迭代了这个游标,返回一组初始的结果,并允许我们使用it命令继续迭代。

但是我们还可以直接使用cursor;在下面的章节中会讨论该怎么做。

从查询中获取数据

前面我们讨论了任何深度的查询,接下来我们讲讲如果使用查询结果工作-一个游标对象。我们将使用简单的find()查询函数,它会返回集合中的任何内容,后面会讲如果创建特殊的查询。

为了使用mongo shell来查看集合中的所有元素,我们需要显式的使用find()操作返回的游标。

让我们再做一次相同的查询,但是这次使用find()返回的游标,然后在while循环中迭代它:

  1. > var cursor = db.things.find();  
  2. > while (cursor.hasNext()) printjson(cursor.next());  
  3. { "_id" : ObjectId("4c2209f9f3924d31102bd84a"), "name" : "mongo" }  
  4. { "_id" : ObjectId("4c2209fef3924d31102bd84b"), "x" : 3 }  
  5. { "_id" : ObjectId("4c220a42f3924d31102bd856"), "x" : 4, "j" : 1 }  
  6. { "_id" : ObjectId("4c220a42f3924d31102bd857"), "x" : 4, "j" : 2 }  
  7. { "_id" : ObjectId("4c220a42f3924d31102bd858"), "x" : 4, "j" : 3 }  
  8. { "_id" : ObjectId("4c220a42f3924d31102bd859"), "x" : 4, "j" : 4 }  
  9. { "_id" : ObjectId("4c220a42f3924d31102bd85a"), "x" : 4, "j" : 5 }  
  10. { "_id" : ObjectId("4c220a42f3924d31102bd85b"), "x" : 4, "j" : 6 }  
  11. { "_id" : ObjectId("4c220a42f3924d31102bd85c"), "x" : 4, "j" : 7 }  
  12. { "_id" : ObjectId("4c220a42f3924d31102bd85d"), "x" : 4, "j" : 8 }  
  13. { "_id" : ObjectId("4c220a42f3924d31102bd85e"), "x" : 4, "j" : 9 }  
  14. { "_id" : ObjectId("4c220a42f3924d31102bd85f"), "x" : 4, "j" : 10 }  
  15. { "_id" : ObjectId("4c220a42f3924d31102bd860"), "x" : 4, "j" : 11 }  
  16. { "_id" : ObjectId("4c220a42f3924d31102bd861"), "x" : 4, "j" : 12 }  
  17. { "_id" : ObjectId("4c220a42f3924d31102bd862"), "x" : 4, "j" : 13 }  
  18. { "_id" : ObjectId("4c220a42f3924d31102bd863"), "x" : 4, "j" : 14 }  
  19. { "_id" : ObjectId("4c220a42f3924d31102bd864"), "x" : 4, "j" : 15 }  
  20. { "_id" : ObjectId("4c220a42f3924d31102bd865"), "x" : 4, "j" : 16 }  
  21. { "_id" : ObjectId("4c220a42f3924d31102bd866"), "x" : 4, "j" : 17 }  
  22. { "_id" : ObjectId("4c220a42f3924d31102bd867"), "x" : 4, "j" : 18 }  
  23. { "_id" : ObjectId("4c220a42f3924d31102bd868"), "x" : 4, "j" : 19 }  
  24. { "_id" : ObjectId("4c220a42f3924d31102bd869"), "x" : 4, "j" : 20 }  


上面的例子显示了游标风格的迭代。hasNext()函数告诉我们是否还有文档可以返回,next()函数则返回下一个文档。我们还使用了内置的printjson()方法将文档翻译为漂亮的JSON风格的格式。

当在JavaScript shell下面工作,我们还可以使用该语言实用的基本组件,然后对游标调用forEach。重复上面的例子,但是对游标不再使用while循环,而是直接使用forEach():

  1. > db.things.find().forEach(printjson);  
  2. { "_id" : ObjectId("4c2209f9f3924d31102bd84a"), "name" : "mongo" }  
  3. { "_id" : ObjectId("4c2209fef3924d31102bd84b"), "x" : 3 }  
  4. { "_id" : ObjectId("4c220a42f3924d31102bd856"), "x" : 4, "j" : 1 }  
  5. { "_id" : ObjectId("4c220a42f3924d31102bd857"), "x" : 4, "j" : 2 }  
  6. { "_id" : ObjectId("4c220a42f3924d31102bd858"), "x" : 4, "j" : 3 }  
  7. { "_id" : ObjectId("4c220a42f3924d31102bd859"), "x" : 4, "j" : 4 }  
  8. { "_id" : ObjectId("4c220a42f3924d31102bd85a"), "x" : 4, "j" : 5 }  
  9. { "_id" : ObjectId("4c220a42f3924d31102bd85b"), "x" : 4, "j" : 6 }  
  10. { "_id" : ObjectId("4c220a42f3924d31102bd85c"), "x" : 4, "j" : 7 }  
  11. { "_id" : ObjectId("4c220a42f3924d31102bd85d"), "x" : 4, "j" : 8 }  
  12. { "_id" : ObjectId("4c220a42f3924d31102bd85e"), "x" : 4, "j" : 9 }  
  13. { "_id" : ObjectId("4c220a42f3924d31102bd85f"), "x" : 4, "j" : 10 }  
  14. { "_id" : ObjectId("4c220a42f3924d31102bd860"), "x" : 4, "j" : 11 }  
  15. { "_id" : ObjectId("4c220a42f3924d31102bd861"), "x" : 4, "j" : 12 }  
  16. { "_id" : ObjectId("4c220a42f3924d31102bd862"), "x" : 4, "j" : 13 }  
  17. { "_id" : ObjectId("4c220a42f3924d31102bd863"), "x" : 4, "j" : 14 }  
  18. { "_id" : ObjectId("4c220a42f3924d31102bd864"), "x" : 4, "j" : 15 }  
  19. { "_id" : ObjectId("4c220a42f3924d31102bd865"), "x" : 4, "j" : 16 }  
  20. { "_id" : ObjectId("4c220a42f3924d31102bd866"), "x" : 4, "j" : 17 }  
  21. { "_id" : ObjectId("4c220a42f3924d31102bd867"), "x" : 4, "j" : 18 }  
  22. { "_id" : ObjectId("4c220a42f3924d31102bd868"), "x" : 4, "j" : 19 }  
  23. { "_id" : ObjectId("4c220a42f3924d31102bd869"), "x" : 4, "j" : 20 }  


在forEach()的实例中,我们必须为游标定义一个函数,对于每一个文档它都会被调用。

在mongo shell,你处理游标还可以像处理数组:

  1. > var cursor = db.things.find();  
  2. > printjson(cursor[4]);  
  3. { "_id" : ObjectId("4c220a42f3924d31102bd858"), "x" : 4, "j" : 3 }  


当以这种方式使用游标时,注意所有的值直到访问的最大值(上面是cursor[4])都会被同时装载到RAM中。这对于很大的结果集是不合适的,因为你会耗尽内存。对于任何返回大量元素的查询,游标应当作为迭代器来使用。

除了以数组风格来访问游标,你可以将游标转换为一个真正的数组:

  1. > var arr = db.things.find().toArray();  
  2. > arr[5];  
  3. { "_id" : ObjectId("4c220a42f3924d31102bd859"), "x" : 4, "j" : 4 }  


请注意这种数组特性仅适用于mongo-交互型shell,并不是所有的驱动都提供这种功能。

mongodb游标不是快照-在你第一次和最后一次调用next()中间,游标可能返回或者不返回你或者其他用户在这个集合中所执行的操作。使用显式的锁动作来执行一个快照型的查询。

指定查询的返回值

现在我们已经知道了如果使用查询返回的游标工作,让我们关注怎么定制查询去返回特定的内容。

通常的方法就是创建"查询文档",这个查询文档指出了需要匹配的键和值的样式。

相比于解释,这些更容易演示。在接下来的例子中,我们会给出SQL查询例子,然后演示如何通过mongo shell来表达相同的查询。这种指定查询的方法在mongodb中是很基础的,所以你将能在所有的驱动或者语言中找到相同的通用的功能。

  1. SELECT * FROM things WHERE name="mongo"  
  1. > db.things.find({name:"mongo"}).forEach(printjson);  
  2. { "_id" : ObjectId("4c2209f9f3924d31102bd84a"), "name" : "mongo" }  
  1. SELECT * FROM things WHERE x=4  
  1. > db.things.find({x:4}).forEach(printjson);  
  2. { "_id" : ObjectId("4c220a42f3924d31102bd856"), "x" : 4, "j" : 1 }  
  3. { "_id" : ObjectId("4c220a42f3924d31102bd857"), "x" : 4, "j" : 2 }  
  4. { "_id" : ObjectId("4c220a42f3924d31102bd858"), "x" : 4, "j" : 3 }  
  5. { "_id" : ObjectId("4c220a42f3924d31102bd859"), "x" : 4, "j" : 4 }  
  6. { "_id" : ObjectId("4c220a42f3924d31102bd85a"), "x" : 4, "j" : 5 }  
  7. { "_id" : ObjectId("4c220a42f3924d31102bd85b"), "x" : 4, "j" : 6 }  
  8. { "_id" : ObjectId("4c220a42f3924d31102bd85c"), "x" : 4, "j" : 7 }  
  9. { "_id" : ObjectId("4c220a42f3924d31102bd85d"), "x" : 4, "j" : 8 }  
  10. { "_id" : ObjectId("4c220a42f3924d31102bd85e"), "x" : 4, "j" : 9 }  
  11. { "_id" : ObjectId("4c220a42f3924d31102bd85f"), "x" : 4, "j" : 10 }  
  12. { "_id" : ObjectId("4c220a42f3924d31102bd860"), "x" : 4, "j" : 11 }  
  13. { "_id" : ObjectId("4c220a42f3924d31102bd861"), "x" : 4, "j" : 12 }  
  14. { "_id" : ObjectId("4c220a42f3924d31102bd862"), "x" : 4, "j" : 13 }  
  15. { "_id" : ObjectId("4c220a42f3924d31102bd863"), "x" : 4, "j" : 14 }  
  16. { "_id" : ObjectId("4c220a42f3924d31102bd864"), "x" : 4, "j" : 15 }  
  17. { "_id" : ObjectId("4c220a42f3924d31102bd865"), "x" : 4, "j" : 16 }  
  18. { "_id" : ObjectId("4c220a42f3924d31102bd866"), "x" : 4, "j" : 17 }  
  19. { "_id" : ObjectId("4c220a42f3924d31102bd867"), "x" : 4, "j" : 18 }  
  20. { "_id" : ObjectId("4c220a42f3924d31102bd868"), "x" : 4, "j" : 19 }  
  21. { "_id" : ObjectId("4c220a42f3924d31102bd869"), "x" : 4, "j" : 20 }  

查询表达式就是文档本身。形如{a:A,b:B,...}的查询文档意思是"where a--A and b==B and...".更多关于查询能力的信息可以参阅查询和游标。

MongoDB还允许只返回"部分文档"-这些文档仅包含数据库中文档元素的一个子集。

实现这个功能,你在find()查询函数中增加第二个参数,提供一个需要返回元素列表的文档就可以了。

为了演示这个功能,我们使用增加一个限制仅返回”j“元素的参数来重复上一个find({x:4})的例子:

  1. SELECT j FROM things WHERE x=4  
  1. > db.things.find({x:4}, {j:true}).forEach(printjson);  
  2. { "_id" : ObjectId("4c220a42f3924d31102bd856"), "j" : 1 }  
  3. { "_id" : ObjectId("4c220a42f3924d31102bd857"), "j" : 2 }  
  4. { "_id" : ObjectId("4c220a42f3924d31102bd858"), "j" : 3 }  
  5. { "_id" : ObjectId("4c220a42f3924d31102bd859"), "j" : 4 }  
  6. { "_id" : ObjectId("4c220a42f3924d31102bd85a"), "j" : 5 }  
  7. { "_id" : ObjectId("4c220a42f3924d31102bd85b"), "j" : 6 }  
  8. { "_id" : ObjectId("4c220a42f3924d31102bd85c"), "j" : 7 }  
  9. { "_id" : ObjectId("4c220a42f3924d31102bd85d"), "j" : 8 }  
  10. { "_id" : ObjectId("4c220a42f3924d31102bd85e"), "j" : 9 }  
  11. { "_id" : ObjectId("4c220a42f3924d31102bd85f"), "j" : 10 }  
  12. { "_id" : ObjectId("4c220a42f3924d31102bd860"), "j" : 11 }  
  13. { "_id" : ObjectId("4c220a42f3924d31102bd861"), "j" : 12 }  
  14. { "_id" : ObjectId("4c220a42f3924d31102bd862"), "j" : 13 }  
  15. { "_id" : ObjectId("4c220a42f3924d31102bd863"), "j" : 14 }  
  16. { "_id" : ObjectId("4c220a42f3924d31102bd864"), "j" : 15 }  
  17. { "_id" : ObjectId("4c220a42f3924d31102bd865"), "j" : 16 }  
  18. { "_id" : ObjectId("4c220a42f3924d31102bd866"), "j" : 17 }  
  19. { "_id" : ObjectId("4c220a42f3924d31102bd867"), "j" : 18 }  
  20. { "_id" : ObjectId("4c220a42f3924d31102bd868"), "j" : 19 }  
  21. { "_id" : ObjectId("4c220a42f3924d31102bd869"), "j" : 20 }  


注:默认情况下"_id"域始终会返回。

findOne()-语法便利

简便起见,mongo shell(和其他的驱动)允许通过findOne()函数仅返回一个文档,避免了程序从头开始处理游标。findOne()接受与find()方法相同 的参数,但是不再返回游标,而是返回要么数据库中第一个符合的文档,要么返回null如果没有匹配到。

作为例子,我们检索一个符合"name=="mongo""的文档。除了对游标调用next()(当然首先判断是否为空)或者将游标当做数组处理读取0th元素,还有很多方法可以使用、

无论如何,findOne()方法方便并且高效:

  1. > printjson(db.things.findOne({name:"mongo"}));  
  2. { "_id" : ObjectId("4c2209f9f3924d31102bd84a"), "name" : "mongo" }  


这个方法更加高效,是因为客户端向数据库请求单个对象,这样数据库和网络和以前相比只做少量的工作。它等效于find({name:"mogno"}).limit(1).

另外一个使用_id查询单个文档的例子:

  1. > var doc = db.things.findOne({_id:ObjectId("4c2209f9f3924d31102bd84a")});  
  2. > doc  
  3. { "_id" : ObjectId("4c2209f9f3924d31102bd84a"), "name" : "mongo" }  

使用limit()限制返回个数

你可以通过limit()函数来设定返回结果的最大个数,从而限定了查询结果的数据大小。

由于性能的原因它是强烈推荐使用的,这样就限定了数据库需要做的工作,限定了需要通过网络返回的数据量大小。例如:

  1. > db.things.find().limit(3);  
  2. { "_id" : ObjectId("4c2209f9f3924d31102bd84a"), "name" : "mongo" }  
  3. { "_id" : ObjectId("4c2209fef3924d31102bd84b"), "x" : 3 }  
  4. { "_id" : ObjectId("4c220a42f3924d31102bd856"), "x" : 4, "j" : 1 }  

更多帮助

除了使用"help"命令,你还可以在db和db.whatever上面调用help去查看可用的方法。

如果你很好奇某个函数内部在做什么,你可以输入函数名(不要())shell会打印出源代码,例如:

  1. > printjson  
  2. function (x) {  
  3. print(tojson(x));  
  4. }  


mongo是一个完全的JavaScript shell,因此任何JavaScript函数,语法,或者类都可以在该shell中使用。另外,mongodb也定义了一些自己的类和全局变量(如db). 你可以http://api.mongodb.org/js/在查看完整的API.

https://github.com/tomliugen
原文地址:https://www.cnblogs.com/xinghebuluo/p/2266196.html