本篇学习笔记主要来源于:http://www.runoob.com/mongodb/mongodb-tutorial.html
MongoDB中将表称为集合,将行称为文档,将列称为字段
Robo客户端双击表出现下图所示页面,展示这个表里的所有数据
1、Mongo基础语法
(1)创建集合
db.createCollection(“集合名”),若当前用户权限较高,先切换到对应数据库,eg:use test
eg:db.createCollection(“weijie_test”)
可以创建固定大小的集合
字段 | 类型 | 描述 |
capped | 布尔 | (可选)若为true,则创建固定大小的集合,当达到最大值时,自动覆盖最早的文档。若为true,必须指定size参数。 |
autoIndexId | 布尔 | (可选)若为true,自动在_id字段创建索引。默认false |
size | 数值 | (可选)为固定集合指定最大值(以字节计)。 |
max | 数值 | (可选)指定固定集合中包含文档的最大数量。 |
直接插入数据到一个不存在的集合也能够自动创建集合
(2)删除集合
db.集合名.drop()
eg:db.weijie_test.drop()
(3)插入
db.collectionName.insert({key1:’value1’,key2,:value2})
若集合原来不存在,则插入操作会创建一个集合并插入数据;
若多次插入的数据字段数量不一致,比如集合里原来只有5个字段,在某次插入时插入了6个字段,则集合会变成6个字段,之前只有5个字段的文档会自动补上这个字段,但是记录是空(不是null)
eg:db.weijie_test.insert({name:’zhangsan’,age:18,sex:’man’,company:’yoyo’,department:’IT’,province:’hubei’})
也可以先定义一个对象,对象的内容是集合的字段和值,json格式,然后使用插入插入语句,传递对象,eg:
document=({name:'lisi',age:20,sex:'woman',company:'hoho',department:'develop',province:'shanxi'})
db.weijie_test.insert(document)
还可以使用db.weijie_test.save(document)完成插入,如果不指定_id,save()类似insert(),如果指定_id,则会更新该条记录
插入多条记录时,每条记录用{}包含,然后将所有的记录用[]包含(若不用[]会抛异常),eg:
db.weijie_test.insert([{name:'wangwu',age:18,sex:'man',company:'yoyo',department:'IT',province:'hubei'},
{name:'zhaoliu',age:22,sex:'woman',company:'tt'},
{name:'enen',age:32,sex:'woman',province:'henan'}])
(4)查询
db.collectionName.find(query,projection)
参数 | 类型 | 描述 |
query |
| 可选,查询条件,若不填则查询集合里的所有数据 |
projection |
| 可选,指定返回的键,若不填则返回一条记录 |
按某个字段查询这个表里的一条记录
db.collecionName.find({fieldName:’value’}),若要按多个字段联合查询,可以在()里面加{}填上相应字段名和值
eg:db.weijie_test.find({name:'zhangsan'})
或者db.getCollection(‘collectionName’).find({}),find里面不填参数时为查询集合里的所有数据,不带参数时里面的{}可以省略
db.getCollection('weijie_test').find()
与RDBMS where语句比较
操作 | 格式 | 样例 | RDBMS类似语句 |
= | {key:value} | db.weijie_test.find({age:20}) | where age=20 |
< | {key:{$lt:value}} | db.weijie_test.find({age:{$lt:20}}) | where age<20 |
<= | {key:{$lte:value}} | db.weijie_test.find({age:{$lte:20}}) | where age<=20 |
> | {key:{$gt:value}} | db.weijie_test.find({age:{$gt:20}}) | where age>20 |
>= | {key:{$gte:value}} | db.weijie_test.find({age:{$gte:20}}) | where age>=20 |
!= | {key:{$ne:value}} | db.weijie_test.find({age:{$ne:20}}) | where age!=20 |
猜测字母含义:
l:less、t:than、e:equal、g:greater、n:not
查询条件有多个字段表示and关系,or关系用$or
db.collectionName.find(
{
$or: [
{key1:value1}, {key2:value2}
]
}
)
eg:
db.weijie_test.find(
{
$or:[
{age:20},{department:'IT'}
]
}
)
and与or公用,eg:
db.weijie_test.find(
{company:'yoyo',
$or:[
{age:20},{department:'IT'}
]
}
)
模糊查询
{key:/value/},指key的值包含value的记录
{key:/^value/},指key的值以value开头的记录
{key:/value$/},指key的值以value结尾的记录
(5)更新
使用update()和save()更新集合中的文档
使用update更新文档
db.collectionName.update(
<query>
<update>,
{
upsert:<boolean>,
multi:<boolean>,
writeConcern:<document>
}
)
参数 | 类型 | 描述 |
query |
| 查询条件,类似sql update查询内where后面的 |
update |
| 需要更新的对象和操作符($,$inc…)等,类似sql update查询内set后面的 |
upsert | boolean | 可选,如果不存在需要更新的记录,是否插入新记录,默认false |
multi | boolean | 可选,更新时可能查到多条记录,false为更新第一条,true为全部更新,默认false |
writeConcern | document | 可选,抛出异常的级别 |
eg:
db.weijie_test.update({name:'zhangsan'},{$set:{age:25}})//只会修改查到的第一条
db.weijie_test.update({name:'zhangsan'},{$set:{age:19}},{multi:true})//会修改所有查到的
使用save()更新文档
db.collectionName.save(
<document>,
{
writeConcern: <document>
}
)
参数 | 类型 | 描述 |
document | 文档变量 | 文档数据 |
writeConcern |
| 可选,抛出异常的级别 |
eg:
db.weijie_test.save({
_id : ObjectId("5b9a2a514c755630fbd79a2f"),
name : "zhangsansan",
age : 56.0,
sex : "xx",
company : "mofine",
department : "IT"
})
可以看到,某个字段不传时,会置为空
(6)删除
db.collectionName.remove(
<query>,
<justOne>
)
2.6以后的版本:
db.collectionName.remove(
<query>,
{
justOne: <boolean>,
writeConcern: <document>
}
)
参数 | 类型 | 描述 |
query |
| 可选,删除文档的条件 |
justOne | boolean | 可选,若设为true或1,则只删除一条文档 |
writeConcern | 文档变量 | 可选,抛出异常的类型 |
eg:db.weijie_test.remove({name:'zhangsansan'})
(7)数据类型
查询某个字段为某个数据类型的记录,使用{$type:数据类型或对应的数字}
类型 | 数字 | 备注 |
Double | 1 |
|
String | 2 |
|
Object | 3 |
|
Array | 4 |
|
Binary data | 5 |
|
Undefined | 6 | 已废弃 |
Object id | 7 |
|
Boolean | 8 |
|
Date | 9 |
|
Null | 10 |
|
Regular Expression | 11 |
|
JavaScript | 13 |
|
Symbol | 14 |
|
JavaScript(with scope) | 15 |
|
32-bit integer | 16 |
|
Timestamp | 17 |
|
64-bit integer | 18 |
|
Min key | 255 | Query with-1 |
Max key | 127 |
|
eg:查询集合中name字段为String的记录
db.weijie_test.find({name:{&type:2}})
或db.weijie_test.find({name:{&type:’string’}})
(7)排序
使用sort()排序,指定关键字,1为升序,-1为降序
eg:db.weijie_test.find().sort({name:1})
注:此时如果字段填错也不会抛异常,只是不会排序而已;升序时空字段排前面,降序时空字段排后面
(8)索引
db.collectionName.createIndex(keys, options)
key表示需要创建索引的字段,1为升序,-1为降序;支持根据多个字段创建复合索引
(9)聚合
聚合在查询时必须指定一个字段,该字段又分为加$和不加的
格式:db.collectionName.aggregate([{$group:{_id:’key1’,aggregate_operation:{$operaton:’key2’}}}])
解释:按key1查询,按key2进行operation操作
统计某字段的记录条数(其实就是统计集合的所有记录条数)
eg:db.weijie_test.aggregate([{$group:{_id:"company",num_tutorial:{$sum:1}}}])
等价于select count(company) from weijie_test//记录中compan为空的不会计入
统计某字段的各个值的记录条数
eg:db.weijie_test.aggregate([{$group:{_id:"$company",num_tutorial:{$sum:1}}}])
对字段加上$后,效果如图:
操作 | 描述 | 举例 |
&sum | 求和 | db.weijie_test.aggregate([{$group:{_id:’$key1’,num_tutorial:{$sum:’$key2’}}}]) |
$avg | 求平均 | db.weijie_test.aggregate([{$group:{_id:’$key1’,num_tutorial:{$avg:’$key2’}}}]) |
$min | 取最小值 | db.weijie_test.aggregate([{$group:{_id:’$key1’,num_tutorial:{$min:’$key2’}}}]) |
$max | 取最大值 | db.weijie_test.aggregate([{$group:{_id:’$key1’,num_tutorial:{$max:’$key2’}}}]) |
$push | 插入值到数组 | db.weijie_test.aggregate([{$group:{_id:’$key1’,url:{$push:’key2’}}}]) |
$addToSet | 插入值到数组,但不创建副本 | db.weijie_test.aggregate([{$group:{_id:’$key1’,url:{$addToSet:’key2’}}}]) |
$first | 根据排序获取第一个文档数据 | db.weijie_test.aggregate([{$group:{_id:’$key1’,first_url:{$first:’$key2’}}}]) |
$last | 根据排序获取最后一个数据 | db.weijie_test.aggregate([{$group:{_id:’$key2’,last_url:{$last:’$key2’}}}]) |
管道:MongoDB的聚合管道将MonoDB文档在一个管道处理完毕后将结果传递给下一个管道处理。
实现的效果如:只查文档的某些列(project);查询某列在某些范围的文档(match)
操作 | 描述 | 举例 | 类比SQL |
$project | 修改输入文档的结构。可重命名、增加、删除域,也可用于创建计算结果以及嵌套文档 | db.weijie_test.aggregate({ $project:{ name:1,age:1,courses:1}}) | select name,age,courses from weijie_test |
$match | 过滤数据,只展示符合范围的数据 | db.weijie_test.aggregate( {$match:{age:{$gte:20,$lte:35}}}) | Select * from weijie_test where age between 20 and 35 |
$limit | 限制返回的文档数 |
|
|
$skip | 跳过指定数量的文档,并返回余下文档 |
|
|
$unwind | 将文档文档中某个数组类型的字段拆成多条 | db.weijie_test2.aggregate({ $unwind:'$courses' }) | 这里courses字段为空的记录不会展示,$必须带 |
$group |
|
|
|
$sort |
|
|
|
$geoNear |
|
|
|
(10)limit()、skip()
limit(number)用于限定记录条数为number条
eg:db.weijie_test.find().limit(2)//查询前2条记录
skip(number)用于跳过number条记录
eg:db.weijie_test.find().limit(2).skip(1)//查询2条记录,但是跳过第一条(返回的结果是第2条和第3条,即先执行skip)
如果sort()、limit()、skip()合用,则执行顺序sort>skip>limit
文档键命名规范:
1、键不能含有\0(空字符串)。这个字符表示键的结尾
2、.和$有特别的意义,只有特定环境下才能使用
3、以下划线”_”开头的键是保留的(不是严格要求的)
常用命令
show dbs 展示当前的数据库(权限要求较高)
show collections 展示当前数据库中的集合
2、MongoDB Java
MongoDB的连接分为认证和无认证的,这取决于服务端,实际应用中一般是需要认证的。与SQL不同的是,Mongo的操作先获取集合(表),然后操作,而不是SQL那样表写到sql中。
这里用的Mongo驱动为mongo-java-driver-3.8.1.jar,为当前最新版本,下载地址:http://mongodb.github.io/mongo-java-driver/
package test;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import com.mongodb.ServerAddress;
import com.mongodb.MongoCredential;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCursor;
import org.bson.Document;
public class TestDB {
public static void main(String[] args)
{
String mongoHost = "****";
int mongoPort = 27017;
String user = "***";
String database = "***";
String pwd = "***";
String collection = "weijie_test";
//这里的MongoClient其实是MongoDB的连接池,可通过MongoClientOptions.Builder配置连接池设置,然后创建MongoClient
MongoClient client = getMongoClient(mongoHost,mongoPort,user,database,pwd);
MongoDatabase db = client.getDatabase(database);
Map<String,Object> data = new HashMap<String,Object>();
data.put("name", "haha");
data.put("age", 28.0);
data.put("sex", "man");
data.put("company", "aqiyi");
Map<String,Object> data2 = new HashMap<String,Object>();
data2.put("age", 29.2);
data2.put("province", "xinjiang");
Map<String,Object> data3 = new HashMap<String,Object>();
data3.put("name", "haha");
data3.put("province", "henan");
insert(db,collection,data);
select(db,collction);
update(db,collection,data2);
deleteOne(db,collection,data3);
}
//无认证的连接
public static MongoDatabase getMongoClient(String host, int port, String database)
{
MongoClient client = new MongoClient(host,port);
MongoDatabase db = client.getDatabase(database);
System.out.println("成功连接Mongo!");
return db;
}
public static MongoClient getMongoClient(String host, int port, String user, String database, String pwd)
{
ServerAddress address = new ServerAddress(host,port);
List<ServerAddress> adds = new ArrayList<ServerAddress>();
adds.add(address);
//MongoCredential credential = MongoCredential.createScramSha1Credential(user, database, pwd.toCharArray());
MongoCredential credential = MongoCredential.createCredential(user,database,pwd.toCharArray());
List<MongoCredential> credentials = new ArrayList<MongoCredential>();
credentials.add(credential);
//获取Mongo的连接池
MongoClient client = new MongoClient(adds,credentials);
return client;
}
public static boolean createCollection(MongoDatabase db, String collectionName)
{
boolean result = false;
if(db==null ||(collectionName ==null ||collectionName.trim() =="")) return result;
try{
db.createCollection(collectionName);
}catch(Exception e){
e.printStackTrace();
System.out.println("创建集合失败");
return result;
}
return true;
}
public static void insert(MongoDatabase db, String table, Map<String,Object> dataMap)
{
MongoCollection<Document> collection = db.getCollection(table);
/*
//String key;
Document doc = new Document();
for(String key:dataMap.keySet())
{
doc.append(key, dataMap.get(key));
}*/
Document doc = new Document(dataMap);
List<Document> documents = new ArrayList<Document>();
documents.add(doc);
collection.insertMany(documents);
}
public static void select(MongoDatabase db, String table)
{
MongoCollection<Document> collection = db.getCollection(table);
FindIterable<Document> findIterable = collection.find();
MongoCursor<Document> cursor = findIterable.iterator();
while(cursor.hasNext())
{
System.out.println(cursor.next());
}
}
public static void update(MongoDatabase db, String table, Map<String,Object> dataMap)
{
//dataMap.put("age", 29.2);
//dataMap.put("province", "xinjiang");
MongoCollection<Document> collection = db.getCollection(table);
//此处的$set是何意?
collection.updateMany(Filters.eq("name", "haha"), new Document("$set",new Document(dataMap)));
}
public static void deleteOne(MongoDatabase db, String table, Map<String,Object> map)
{
MongoCollection<Document> collection = db.getCollection(table);
//删除符合条件的第一条文档
for(String key : map.keySet())
{
collection.deleteOne(Filters.eq(key, map.get(key)));
}
//删除符合条件的所有文档
//collection.deleteMany(Filters.eq(key, map.get(key)));
}
}
举例:
查询集合中某日期之前的记录数
var cursor = db.getCollection('ReportInfo').find({"creationDate":{$lte:ISODate("2018-01-12")}});
var size = 0;
cursor.forEach(
function(doc){
size += Object.bsonsize(doc)
}
);
print(size);