MongoDB入门





连接数据库



在这里我们使用MongoDB提供的JavaScript shell进行数据库操作,当然也可以通过不同的驱动利用其他编程语言实现同样的功能,不过shell在管理数据库的方面还是很方便的。



启动JavaScript shell的方法很简单,命令如下:





C:\mongodb\bin\mongo





在默认情况下,shell连接到本地test数据库,可以看到如下信息:





C:\mongodb\bin>mongo



MongoDB shell version: 2.0.2



connecting to: test



>





connecting to”的后面是要连接的数据库的名字,如果想换成其他的数据库,可以用如下命令:





> use mydb



switched to
dbmydb







注意:切换数据库后,如果切换的数据库不存在,系统并不会马上创建这个数据库,而是在对它进行第一次插入操作时才创建。这意味着当你使用“show dbs”命令查看现有数据库时,并不能看到切换的数据库。





动态模式(无模式)



MongoDB包含数据库(database)、集合(collection),以及和传统关系数据库很相似的索引结构(index)。对于数据库和集合这些对象(object),系统会隐式地进行创建,然而一旦创建它们就被记录到了系统目录中(db.systems.collectionsdb.system.indexes)。



集合由文档(document)组成,文档中包含域(field),也就是传统关系数据库中的字段。但与关系数据库不同,MongoDB不会对域进行预定义,也没有给文档定义模式,这就意味着文档中不同域和它们的值是可以变化的。因此,MongoDB并没有“alter table”操作来增加或者减少域的个数。在实际应用中,一个文档中通常包含相同类型的结构,但这并不是必须的。这种弹性使得模式变动或者增加变得非常容易,几乎不用写任何脚本程序就可实现“alter table”操作。另外,动态模式机制便于对基于MongoDB数据库的软件进行重复性开发,大大减少了由于模式变化所带来的工作量。



向集合中插入数据



首先创建一个名为test的集合,再向test中插入数据。我们创建两个对象jt,然后将它们保存到集合things中。



在下面的例子中,“>”表示shell命令提示符:





>j={name:"mongo"}



{ "name" : "mongo" }



> t={x:3}



{ "x" : 3 }



>db.things.save(j)



>db.things.save(t)



>db.things.find()



{ "_id" : ObjectId("4f361b1f64480e0bcb6d6021"),
"name" : "mongo" }



{ "_id" : ObjectId("4f361c6364480e0bcb6d6022"),
"x" : 3 }



>







注意:



? 我们并没有预定义集合,数据库是在进行第一次插入操作时自动创建集合的。



? 我们存储的文档包含不同的域,在这个例子中,文档中没有相同的数据元素。但在实际

     
应用中,往往把相同结构的数据存储在一个集合中。



? 一旦被存储到数据库中,如果没有事先定义,对象就会被自动分配一个ObjectId,并且

     
存储到field_id域中。当你运行上面的例子时,会有不同的ObjectId





向集合中增加更多的记录,下面的代码利用了循环结构:





> for (var i=1; i



>db.things.find()



{ "_id" : ObjectId("4f361b1f64480e0bcb6d6021"),
"name" : "mongo" }



{ "_id" : ObjectId("4f361c6364480e0bcb6d6022"),
"x" : 3 }



{ "_id" : ObjectId("4f36234964480e0bcb6d6023"), "x" : 4,
"j" : 1 }



……



{ "_id" : ObjectId("4f36234964480e0bcb6d6034"), "x" : 4,
"j" : 18 }



has more



>





值得注意的是,上面例子中没有显示出全部的文档,shell默认显示的数目是20。如果想查看其余的文档,可以使用it命令:





{ "_id" : ObjectId("4f36234964480e0bcb6d6034"), "x" : 4,
"j" : 18 }



has more



>it



{ "_id" : ObjectId("4f36234964480e0bcb6d6035"), "x" : 4,
"j" : 19 }



{ "_id" : ObjectId("4f36234964480e0bcb6d6036"), "x" : 4,
"j" : 20 }



>





严格来讲,find()返回的是指针对象。但是在上面的例子中,我们并没有把指针对象赋予任何变量。所以,shell自动对指针进行迭代,直到给出初始的结果集,我们可以通过it命令显示出其余的信息,但是也可以直接对find()返回的指针进行操作,11.3.3.4节中将对其进行介绍。



查询数据



在讨论数据查询之前,先了解一下如何操作查询结果,即指针对象。我们将使用简单的find()方法,返回集合中全部的文档,之后再讨论如何写出特定的查询语句。



为了了解使用mongo shell时集合中的全部元素,我们需要明确地使用find()方法返回的指针。利用while循环对find()返回的指针进行迭代,实现和前面例子相同的查询结果:





>var cursor=db.things.find()



>while (cursor.hasNext()) printjson(cursor.next())



{ "_id" : ObjectId("4f361b1f64480e0bcb6d6021"),
"name" : "mongo" }



{ "_id" : ObjectId("4f361c6364480e0bcb6d6022"),
"x" : 3 }



{ "_id" : ObjectId("4f36234964480e0bcb6d6023"), "x" : 4,
"j" : 1 }



……



{ "_id" : ObjectId("4f36234964480e0bcb6d6036"), "x" : 4,
"j" : 20 }



>





上面的例子显示了指针迭代器,hasNext()方法判断是否还能返回文档,next()方法返回下一个文档。我们也使用了内置的printjson()方法使文档以JSON形式展现。



当在JavaScript shell下工作时,我们也可以利用JavaScript语言的特征,比如使用forEach输出指针对象。下面的代码输出与上面相同的查询结果,但是在代码中使用forEach而不是while循环:





>db.things.find().forEach(printjson)



{ "_id" : ObjectId("4f361b1f64480e0bcb6d6021"),
"name" : "mongo" }



{ "_id" : ObjectId("4f361c6364480e0bcb6d6022"),
"x" : 3 }



{ "_id" : ObjectId("4f36234964480e0bcb6d6023"), "x" : 4,
"j" : 1 }



……



{ "_id" : ObjectId("4f36234964480e0bcb6d6036"), "x" : 4,
"j" : 20 }



>





在使用forEach()方法的时候,必须为指针指向的每一个文档定义函数(这里用了内置方法printjson())。



mongo shell中,可以像对数组一样操作指针:





>var cursor=db.things.find()



>printjson(cursor[4])



{ "_id" : ObjectId("4f36234964480e0bcb6d6025"), "x" : 4,
"j" : 3 }



>





当用这种方式使用指针时,指针指示的值都能同时加载到内存中,这一点不利于返回较大的查询结果,因为有可能发生内存溢出。对于结果较大的查询,应该用迭代方式输出指针值。



另外,你可以将指针转变为真正的数组进行处理:





>arr[5]



{ "_id" : ObjectId("4f36234964480e0bcb6d6026"), "x" : 4,
"j" : 4 }



>





注意,这些数组特性都仅适用于shell模式,但对于其他语言环境并不适合。MongoDB指针并不是快照,当在集合上进行操作时,如果有其他人在集合里第一次或者最后一次调用next(),那么你的指针可能不能成功返回结果,所以要明确锁定你要查询的指针。



条件查询



我们已经知道如何操作查询返回的指针,现在我们要针对特定条件实现对查询结果的筛选。一般来说,实现条件查询就需要建立“查询文档”,即指明键需要匹配的模式和值的文档。对于这一点用例子证明要比用文字解释清楚得多。在下面的例子中,我们将给出SQL查询,并且说明如何借助mongo
shell
使得MongoDB能实现相同的查询(参见表11-4与表11-5)。这种条件查询是MongoDB的基本功能,所以你也可以用其他程序驱动或者语言实现条件查询。



11-4 
MongoDB
条件查询(name="mongo"







 


 


 

SELECT * FROM things WHERE
  name="mongo"


 

 

>db.things.find({name:"mongo"}).forEach(printjson)


 

{ "_id" :
  ObjectId("4f361b1f64480e0bcb6d6021"), "name"
  : "mongo" }


 

>


 




11-5 
MongoDB
条件查询(x=4







 


 


 

SELECT *
  FROM things WHERE x=4


 

 

>db.things.find({x:4}).forEach(printjson)


 

{ "_id" :
  ObjectId("4f36234964480e0bcb6d6023"),
  "x" : 4, "j" : 1 }


 

{ "_id" :
  ObjectId("4f36234964480e0bcb6d6024"),
  "x" : 4, "j" : 2 }


 




续表 







 


 

……


 

{ "_id" :
  ObjectId("4f36234964480e0bcb6d6036"),
  "x" : 4, "j" : 20 }


 

>


 




查询表达式本身是一个文档,一个查询文档{a:Ab:B…}意思是“where a==A and b==B and …”。如果想了解更多条件查询有关的信息,可以到MongoDB官网上查看MongoDB开发者手册,网址如下:



http://www.mongodb.org/display/DOCS/Manual



MongoDB也允许返回“部分文档”,也就是结果中只包含数据库文档的一些子元素,类似于关系数据库中针对某些列的查询。为了实现这个查询,可以在find()方法中增加第二个参数,表示返回某些特定元素。为了便于说明,下面我们还是实现find({x:4})的查询,只不过增加了额外的参数使得结果中只包含j元素:



11-6 
MongoDB
条件查询(返回特定元素j







 


 


 

SELECT j
  FROM things WHERE x=4


 

 

>db.things.find({x:4},{j:true}).forEach(printjson)


 

{ "_id" :
  ObjectId("4f36234964480e0bcb6d6023"),
  "j" : 1 }


 

……


 

{ "_id" :
  ObjectId("4f36234964480e0bcb6d6036"),
  "j" : 20 }


 

>


 






注意:_id”字段总是会返回在结果中的。







作者简介



陆嘉恒,中国人民大学教授,博士生导师。2006年毕业于新加坡国立大学计算机科学系,获博士学位;2006-2008年在美国加利福尼亚大学尔湾分校(University of California, Irvine)进行博士后研究;2008年加入中国人民大学,2012年破格晋升为教授。主要研究领域包括数据库技术和云计算技术。先后在SIGMODVLDBICDEWWW等国际重要会议和期刊上发表数据库方向的论文40多篇,主编多本云计算和大数据的教材和著作。



本文节选自《大数据挑战与NoSQL数据库技术》一书。陆嘉恒 编著,由电子工业出版社出版。



10-28 18:16