MongoDB条件查询
1.自动注入mongo
@Autowired
protected MongoOperations mongo;
@Autowired
protected GridFsOperations gridFs;
2.查询
创建条件对象 Criteria
Criteria criteria;
//等于条件
criteria.where("id").is(id)
//大于等于和小于等于 (>=startTimestamp && <= endTimestamp)
criter.and("saveTime").gte(startTimestamp).lte(endTimestamp);
//大于和小于
criter.and("saveTime").gt(minSaveTime).lt(endTimestamp);
//保存时间不等于
criter.and("saveTime").ne(saveTimeList);
//保存时间在列表内
criter.and("saveTime").in(saveTimeList);
//保存时间不在列表内
criter.and("saveTime").nin(saveTimeList);
MongoDB条件操作符
(>) 大于 - $gt
(<) 小于 - $lt
(>=) 大于等于 - $gte
(<= ) 小于等于 - $lte
创建Query对象
// 创建
Query query = new Query(criteria);
//升序条件
Sort sort = new Sort(Sort.Direction.ASC, "saveTime");
Sort sort2 = new Sort(Sort.Direction.ASC, "id");
Query query = new Query(criteria).with(sort).with(sort2);
// 限制条数
Query query = new Query(criteria).with(sort).limit(pageSize);
// 分页
Query quey=new Query(criteria).with(sort).with(Pageable pageable)
// Pageable对象需要自己实现
//查询
List<T> list= mongo.find(query,Class<T> entityClass); 返回list
内嵌数组查询表达式
(1) $size,用于查询数组大小为size的记录
db.a.find({"comments":{"$size":3}})
表示查询comments数组中含有三个元素的记录。
(2) 查询一个数组的最前n、最后n个元素
db.a.find({},{"addrs":{"$slice":5}}) 返回前5条
db.a.find({},{"addrs":{"$slice":-5}}) 返回后5条
(3) skip
使用Mongodb的时候【其他数据库也类似】,尽量少跳过过多的数据,这样会产生性能问题。
mongodb的skip是用来跳过数据的,但是要少用。需要使用的时候可以用其他方式代替。比如说要对博客 文章分页,那么一般的做法是
db.a.find().sort({"time":1}).skip(10000).limit(10)
优化的做法可能是,根据上一页取出来的时间,在下次分页,即取出下一页的时候,根据上一个时间,来查找,然后再limit,例如
db.a.find({"time":{"$gt":lasttime}}).sort({"time":1}).limit(10)
这样用查找替代跳过数据,效率会有提升。
(4) 查询内嵌数组文档
$elemMatch":{"author":"naughty","score":{"$gt":3}}}})
$elemMatch 将限定条件进行分组,仅当需要对一个内嵌文档的多个键进行查询的时候,才会用到。
(5) 查询内嵌文档
{ "_id" : ObjectId("54af318953b409e1c2efa8d8"), "title" : "iteye", "count" : 4,
"blog" : { "title" : "eksliang.iteye.com", "name" : "ickes" } }
db.iteye.find({"blog.name":"ickes"}}) --查询内嵌文档
(6) 简单数组查询
db.XXX.insert({"names":["BuleRiver1", "BuleRiver2", "BuleRiver3"]});
查询包含BuleRiver1的文档
db.XXX.find({"names":"BuleRiver1"});
查询数组里面同时有BuleRiver1和BuleRiver2才返回
db.XXX.find({"names":{"$all":["BuleRiver1", "BuleRiver2"]}})
如果要返回names数组长度为3的条目,使用$size
db.XXX.find({"names":{"$size":3}});
如果想要返回该数组的前2项,使用$slice
db.XXX.find({"names":{"$slice":2}});
返回后两条:
db.XXX.find({"names":{"$slice":-2}});
从第2条开始,返回3个条目:
db.XXX.find({"names":{"$slice":[2, 3]}});
3.更新操作
mongodb中的update的形式是这样的:
db.XXX.update(query, obj, upsert, multi);
对于upsert(默认为false):
如果upsert=true,如果query找到了符合条件的行,则修改这些行,如果没有找到,则追加一行符合query和obj的行。
如果upsert为false,找不到时,不追加。
对于multi(默认为false):
如果multi=true,则修改所有符合条件的行,否则只修改第一条符合条件的行。
Criteria criter 对象创建方式如上
Query query = new Query(criter);
Update update = new Update();
update.set("userId", activeHistoryData.getUserId())
.set("createdTimestamp", activeHistoryData.getCreatedTimestamp())
.set("updatedTimestamp", activeHistoryData.getUpdatedTimestamp())
.set("totalSteps", activeHistoryData.getTotalSteps())
.set("totalDurations", activeHistoryData.getTotalDurations())
.set("totalCalories", activeHistoryData.getTotalCalories())
.set("totalDistance", activeHistoryData.getTotalDistance());
mongo.upsert(query, update, ActiveHistoryData.class);
“$set” 修改器 和 “$unset”修改器
"$set" 用来指定一个键的键值,如果这个键不存在,则创建它。这对更新模式或者增加用户定义键来说非常方便。
> db.iteye.find() --查看iteye集合,里面有一个blog的内嵌文档
{ "_id" : ObjectId("54af318953b409e1c2efa8d8"), "title" : "iteye", "count" : 4,
"blog" : { "title" : "eksliang.iteye.com", "name" : "ickes" } }
> db.iteye.update({"blog.name":"ickes"},{"$set":{"blog.name":"xl"}}) --用$set修改内嵌文档
> db.iteye.find() --查看当前修改,很明显修改成功
{ "_id" : ObjectId("54af318953b409e1c2efa8d8"), "title" : "iteye", "count" : 4,
"blog" : { "title" : "eksliang.iteye.com", "name" : "xl" } }
"$unset" 就是将文档中的某个键完全删除
> db.user.find({"name":"xl"}) --查询name=xl的文档
{ "_id" : ObjectId("54ae6fb5b94cf1b60f105710"), "name" : "xl", "title" : "MongoD
B" }
> db.user.update({"name":"xl"},{"$unset":{"title":1}}) --删除title这个键(这里删除键的值,官网说为任意数字,我测试时,任何值都是没有任何问题的)
> db.user.find({"name":"xl"}) --再次查看,发现键删除成功
{ "_id" : ObjectId("54ae6fb5b94cf1b60f105710"), "name" : "xl" }
内嵌文档字段更新
//修改resultDetail.diseaseResult.highDiseaseResultDetails的第一个数组元素的multiple的属性值
db.resultTxt.update({"barCode":"111-1146-6104"},
{$set:{"resultDetail.diseaseResult.highDiseaseResultDetails.0.multiple":15}})
(1) 修改器
- $set 和 $unset:修改字段值和删除字段;
- $rename,修改字段名字,
- db.students.update({_id:1},{$rename:{'nickname':'alias','cell':'mobile'}})
- $inc:数字类型字段增减,db.user.update({'name':'owen'},{'$inc':{'age':1}});
- $push和$pushAll:向数组类型末尾追加数据,字段不存在则创建;
- $addToSet:向数组类型追加数据时避免重复;
- $each:遍历数组;
- $pop:从数组中删除数据,{$pop:{key:1}}从末尾删除数据,-1从头部删除;
- $pull和$pullAll:从数组中删除指定数据,db.list.update({},{$pull:{'todo':'undo'}});
- 数组定位修改器:数组可以通过下标定位,也可以通过’$‘定位查询匹配到的记录,db.blog.update({'comments.author':'joe'},{'$set':{'comments.$.author':'jim'}});
(2) $addToSet
是往一个数组里插入每个记录,并保证元素唯一。$addToSet 只有在value1不为数组成员的时候才会添加 value1 到数组中的field。$addToSet 仅能保证集合中项唯一并且不能保证集合中元素的顺序。
db.collection.update( { field: value }, { $addToSet: { field: value1 } } );
$addToSet and $each是往一个数组里插入每个记录,并保证元素唯一,插入一个集合。
db.search_loggers.update({user_id : 2}, {$addToSet : {words : {$each : [ 1, 2, 1, 2, 1]}}}, true)
db.search_loggers.find()
{ "_id" : ObjectId("4f90be7a09ee78ef9db6e01c"), "user_id" : 2, "words" : [ 1, 2 ] }
(3) 删除记录中的一个字段
db.a.update({"xxx":"xxxx"},{"$unset":{"addrs":1}})
(4) $push向数组中增加一个元素,如果数组不存在则创建
db.a.update({},{"$push":{"addrs":"shenzhen"}})
(5) 从数组中删除一个
$pop
db.a.update({},{"$pop":{"addrs":-1}})
-1表示从数组末尾删除。
db.a.update({},{"$pop":{"addrs":1}})
1表示从数组头部删除
$pull
$pull可以删除指定的数组元素
db.a.update({},{"$pull":{"addrs":"shenzhen"}})
4.插入操作
User user = new User("...");
//将user对象保存到"user"这个collection中
mongo.save(user);
//将user对象保存到"new collection"这个collection中
mongo.save("new collection",user);
//将user对象保存到"user"这个collection中
mongo.insert(user);
//将user对象保存到"new collection"这个collection中
mongo.insert("new collection", user);
//将user的对象列表(List)保存到"user"collection中去
mongo.insertList(userInList);
//将user的对象列表(List)保存到"new collection"collection中去
mongo.insertList("new collection", userInList);
saveorupdate的意思。
2) insert的意思是:当记录不存在时插入,而如果记录存在时则忽略,继续插入。
5.删除
WriteResult remove(Object object);
WriteResult remove(Object object, String collection);
WriteResult remove(Query query, Class<?> entityClass);
6.聚合
//计数,查询,返回统计的数量
long count(Query query, Class<?> entityClass);
long count(Query query, String collectionName);
long count(Query query, Class<?> entityClass, String collectionName);
7. 其他操作
$type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,找到bson类型和id对照表。
db.things.find( { a : { $type : 2 } } ); // matches if a is a string
db.things.find( { a : { $type : 16 } } ); // matches if a is an int
$exists:判断字段是否存在;
查询所有存在name字段的记录
db.users.find({name: {$exists: true}});
查询所有不存在phone字段的记录
db.users.find({phone: {$exists: false}});
条件表达式
1)$cond
上文中我们已经看到相关示例,它的作用等同于一个“三元表达式”,语法:
$cond:{if : <boolean-expression>, then : <true-expression>,else : <false-expression> }
2)$ifNull
判定指定表达式是否为null,比如字段不存在(undefined)、值为null。语法:
$ifNull:[<expression>,<return-value expression>]
如果expression的值为null则返回“return-value”。
8.文件存储
GridFS存储小文件。
GridFSDBFile 文件对象类
//GridFS 文件操作对象
@Autowired
protected GridFsOperations gridFs;
9.MongoDB数据库和集合导入导出
//数据库恢复 mongorestore -d mofangdb ./mofangdb20170118/mofangdb/
//数据库备份 mongodump -d mofangdb -o ./mofangdb20170116
单个collection备份
mongoexport -h dbhost -d dbname -c collectionname -f collectionKey -o dbdirectory
-h: MongoDB所在服务器地址
-h, --host=<hostname>
--port=<port>
-d: 需要恢复的数据库实例
-c: 需要恢复的集合
-f: 需要导出的字段(省略为所有字段)
-o: 表示导出的文件名
mongoexport -d mofangdb -c resultTxt -o ./resultTxt.dat
单个collection恢复
mongoimport -d db -c collectionname –type csv –headerline
-d 数据库
-h, --host=<hostname>
--port=<port>
-type: 指明要导入的文件格式
-headerline: 批明不导入第一行,因为第一行是列名
mongoimport -d mofangdb -c collectionname ./
//集合导出 mongoexport -d mofangdb -c resultTxt -o ./resultTxt.dat
//集合导入 mongoimport -d mofangdb -c collectionname ./resultTxt.dat
10. 聚合group by功能
db.sp_listpage.group({
keyf:function(doc){
return {sourceId:doc.sourceId};
},
//统计结果字段
initial:{ count:0,notdownload:0,downloaded:0,geturl:0,faildownload:0,failgeturl:0},
reduce:function(doc,result){
result.count +=1;
if(doc.status == 0){
result.notdownload += 1;
}
if(doc.status == 1){
result.downloaded +=1;
}
if(doc.status == 2){
result.geturl += 1;
}
if(doc.status == -1){
result.faildownload +=1;
}
if(doc.status == -2){
result.failgeturl += 1;
}
},
finalize:function(result){
result.downFailRate = result.faildownload/result.count;
result.parseFailRate = result.failgeturl/result.count;
}
})
staus = 0 //未下载
status = 1 //已下载
status = 2 //解析成功
status = -1 //下载失败
status= -2 //解析失败
根据表中的status字段来统计,不同状态的总数
db.collection.aggregate()
db.collection.aggregate([
{ "$match": { "_id": ObjectId("545b9fa0dd5318a4285f7ce7") } },
{ "$unwind": "$messages" },
{ "$group": {
"_id": "$_id",
"sent": {
"$sum": {
"$cond": [
{ "$eq": [ "$mesages.status", "sent" ] },
1,
0
]
}
},
"pending": {
"$sum": {
"$cond": [
{ "$eq": [ "$messages.status", "pending" ] },
1,
0
]
}
},
"done": {
"$sum": {
"$cond": [
{ "$eq": [ "$messages.status", "done" ] },
1,
0
]
}
}
}}
])
Java实现:
class CustomGroupOperation implements AggregationOperation {
private DBObject operation;
public CustomGroupOperation (DBObject operation) {
this.operation = operation;
}
@Override
public DBObject toDBObject(AggregationOperationContext context) {
return context.getMappedObject(operation);
}
}
DBObject myGroup = (DBObject)new BasicDBObject(
"$group", new BasicDBObject(
"_id","$_id"
).append(
"sent", new BasicDBObject(
"$sum", new BasicDBObject(
"$cond", new Object[]{
new BasicDBObject(
"$eq", new Object[]{ "$messages.status", "sent"}
),
1,
0
}
)
)
).append(
"pending", new BasicDBObject(
"$sum", new BasicDBObject(
"$cond", new Object[]{
new BasicDBObject(
"$eq", new Object[]{ "$messages.status", "pending"}
),
1,
0
}
)
)
).append(
"done", new BasicDBObject(
"$sum", new BasicDBObject(
"$cond", new Object[]{
new BasicDBObject(
"$eq", new Object[]{ "$messages.status", "done"}
),
1,
0
}
)
)
)
);
ObjectId myId = new ObjectId("545b9fa0dd5318a4285f7ce7");
Aggregation aggregation = newAggregation(
match(Criteria.where("_id").is(myId)),
unwind("messges"),
new CustomGroupOperation(myGroup)
);