本文将介绍MongoDB的使用,主要有:
- MongoDB的简介以及导入样例数据;
- Java Driver的概览;
- 基本的CRUD操作和数据聚合( Aggregation);
- 创建索引以提高查询性能。
1.MongoDB的简介以及导入样例数据
MongoDB是一个提供高性能的文档数据库(document database),它通过消除对对象关系模型(ORM)的刚性需求从而促进开发。
Documents:document是指MongoDB中的记录,由field和value对组成。MongoDB中的document与JSON对象相类似。fields对应的values可以包含其他的document,数组document数组。
Collections:在MongoDB中,document是存储在Collections(集合)中的,Collections类似于关系型数据库中的table,但又不是table,因为Collection并不需要它的document拥有同样的模式(schema),如下表示一个restaurants collection:
{
"address": {
"building": "1007",
"coord": [ -73.856077, 40.848447 ],
"street": "Morris Park Ave",
"zipcode": "10462"
},
"borough": "Bronx",
"cuisine": "Bakery",
"grades": [
{ "date": { "$date": 1393804800000 }, "grade": "A", "score": 2 },
{ "date": { "$date": 1378857600000 }, "grade": "A", "score": 6 },
{ "date": { "$date": 1358985600000 }, "grade": "A", "score": 10 },
{ "date": { "$date": 1322006400000 }, "grade": "A", "score": 9 },
{ "date": { "$date": 1299715200000 }, "grade": "B", "score": 14 }
],
"name": "Morris Park Bake Shop",
"restaurant_id": "30075445"
}
2.导入样例数据
a)准备一份数据并命名为primer-dataset.json,如附件所示。
b)将数据导入collection
在命令行或者shell终端,使用mongoimport将准备好的document插入test数据库中的restaurant collection中。
cd /Users/young/Desktop/MongoDB mongoimport --db test --collection restaurants --drop --file primer-dataset.json
如果test中已经存在restaurant collection,该操作将首先会drop掉restaurant collection。
mongoimport 默认连接上一个运行在本地的默认端口为27017的mongod实例。如果需要将数据导入其他的MongoDB,需要使用--host 和 --port 指出主机名和端口号。
3.Java Driver的概览
MongoDB的Java Driver是官方支持的。
a)下载MongoDB的Java驱动和BSON库文件。
http://mongodb.github.io/mongo-java-driver/?_ga=1.254442379.2073848550.1463710724
b)连接到MongoDB
使用com.mongodb.MongoClient类可以连接到运行的mongod实例。可以使用 com.mongodb.client.MongoDatabase接口访问一个指定的MongoDB数据库。
import com.mongodb.MongoClient;
import com.mongodb.client.MongoDatabase;
MongoClient mongoClient = new MongoClient();
MongoDatabase db = mongoClient.getDatabase("test");
4.调用Java驱动实现CRUD功能
a)插入数据
你可以使用insertOne方法将一个document插入到MongoDB的指定的collection中,如果这个collection不存在,MongoDB将会自动创建该collection并执行操作。
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import java.text.DateFormat;
import java.text.ParseException;
public void insertDocument(MongoDatabase db, String collection, Document document) throws ParseException {
// DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'",
// Locale.ENGLISH);
db.getCollection(collection).insertOne(document);
}
这段代码将document插入db.collection中,定义document,可以使用 org.bson.Document :
new Document("address",
new Document()
.append("street", "2 Avenue")
.append("zipcode", "10075")
.append("building", "1480")
.append("coord", asList(-73.9557413, 40.7720266)))
.append("borough", "Manhattan")
.append("cuisine", "Italian")
.append("grades", asList(
new Document()
.append("date", format.parse("2014-10-01T00:00:00Z"))
.append("grade", "A")
.append("score", 11),
new Document()
.append("date", format.parse("2014-01-16T00:00:00Z"))
.append("grade", "B")
.append("score", 17)))
.append("name", "Vella")
.append("restaurant_id", "41704620")
执行插入操作不返回任何结果。如果传递给insertOne的document不包含_id field,Java驱动将会自动增加该field并使用该_id对应的值生成对象id(ObjectId)。插入多个document可以使用 insertMany方法。
b)检索数据
你可以使用find方法发布一个查询从MongoDB中检索数据。在MongoDB中,所有的所有的查询是在一个单独的collection中。查询操作可以返回指定collection中所有的document或者匹配 org.bson.Document定义的过滤标准的document。
public FindIterable<Document> FindCollection(MongoDatabase db, String collection, Document document) {
FindIterable<Document> iterator = null;
if (null == document)
iterator = db.getCollection(collection).find();
else
iterator = db.getCollection(collection).find(document);
return iterator;
}
find方法返回一个生成document的 FindIterable的迭代器对象。
FindIterable<Document> iterator=mongoDBInstance.FindCollection(db,
collection, null);
iterator.forEach(new Block<Document>(){
@Override
public void apply(final Document document) {
System.out.println(document);
}
});
使用MongoDB的Java Driver,用如下的的方式相等:
new Document( <field>, <value> )
如果 <field>是嵌套的,使用点记法访问。Java Driver同事提供了com.mongodb.client.model.Filters描述查询条件,该类提供了很多静态方法方便地创建插叙判断,如eq方法:
eq(<field>, <value>)//等于
lt(<field>, <value>)//小于
gt(<field>, <value>)//大于
查询没有嵌套层的Field:
FindIterable<Document> iterable = mongoDBInstance.getCollection("restaurants").find(
new Document("borough", "Manhattan"));
或者使用Filters:
FindIterable<Document> iterable = mongoDBInstance.getCollection("restaurants").find(
eq("borough", "Manhattan"));
查询一个嵌套的Field:
FindIterable<Document> iterable = mongoDBInstance.getCollection("restaurants").find(
eq("address.zipcode", "10075"));
查询一个数组中的Field:
FindIterable<Document> iterable=mongoDBInstance.getCollection("restaurants").find(eq("grades.grade", "B"));
c)更新document
可以使用 updateOne 、 updateMany、replaceOne方法更新collection中的document,这些方法都接受如下三种参数:
- filtes描述的document匹配规则
- 指定修改部分的document
- 其他可选的参数
需要注意的是_id这个Field是不可以被更新的。
1)更新顶级的Fields
如下代码更新了第一个name是Juni的document,用$set操作更新了cuisine为American (New),同时(append)用$currentDate操作更新了lastModified为当前时间。
mongoDBInstance.getCollection("restaurants").updateOne(new Document("name", "Juni"),
new Document("$set", new Document("cuisine", "American (New)"))
.append("$currentDate", new Document("lastModified", true)));
2)更新嵌套的Field
mongoDBInstance.getCollection("restaurants").updateOne(new Document("restaurant_id", "41156888"),
new Document("$set", new Document("address.street", "East 31st Street")));
updateOne方法返回一个UpdateResult对象,这个对象包含了本次操作的一些信息。如UpdateResult.getModifiedCount()返回这次更新的document的数量。
mongoDBInstance.getCollection("restaurants").updateMany(new Document("address.zipcode", "10016").append("cuisine", "Other"),
new Document("$set", new Document("cuisine", "Category To Be Determined"))
.append("$currentDate", new Document("lastModified", true)));
updateMany方法返回一个UpdateResult对象,这个对象包含了本次操作的一些信息。如UpdateResult.getModifiedCount()返回这次更新的document的数量。
mongoDBInstance.getCollection("restaurants").replaceOne(new Document("restaurant_id", "41704620"),
new Document("address",
new Document()
.append("street", "2 Avenue")
.append("zipcode", "10075")
.append("building", "1480")
.append("coord", asList(-73.9557413, 40.7720266)))
.append("name", "Vella 2"));
replaceOne操作也返回一个UpdateResult对象,这个对象包含了本次操作的一些信息。如UpdateResult.getModifiedCount()返回这次更新的document的数量。
mongoDBInstance.getCollection("restaurants").deleteMany(new Document("borough", "Manhattan"));
mongoDBInstance.getCollection("restaurants").deleteMany(new Document());
mongoDBInstance.getCollection("restaurants").drop();
第一行代码将会删除restaurant中borough为Manhattan的所有document,第二行代码将会删除restaurant中的所有document,但是restaurant本身以及在其上建立的索引,均不会被删除,第三行代码将会达到这种效果。
AggregateIterable<Document> iterable = mongoDBInstance.getCollection("restaurants").aggregate(asList(
new Document("$match", new Document("borough", "Queens").append("cuisine", "Brazilian")),
new Document("$group", new Document("_id", "$address.zipcode").append("count", new Document("$sum", 1)))));
聚集操作是根据指定field的value进行。
new Document(<field1>, <type1>).append(<field2>, <type2>) ...
type为1:升序
mongoDBInstance.getCollection("restaurants").createIndex(new Document("cuisine", 1));
mongoDBInstance.getCollection("restaurants").createIndex(new Document("cuisine", 1).append("address.zipcode", -1));
创建索引的操作没有返回结果。