🌻🌻 目录
一、高级查询
1.1 模糊查询
MongoDB的模糊查询是通过正则表达式的方式实现的。格式为:
/模糊查询字符串/
例如,我要查询userList集合中address字段中含有“shen
”的所有文档,代码如下:
db.userList.find({address:/shen/});
如果要查询name字段中以“
J
”开头的,代码如下:
db.userList.find({name:/^J/});
1.2 Null值处理
如果我们想找出集合中某字段值为空的文档,如何查询呢?其实和我们之前的条件查询是一样的,条件值写为null就可以了。
我们现在集合中的文档都是没有空值的,为了方便测试,现在我们将数据做些修改:
将“Daniel
”的address
改为空
db.userList.update({name:"Daniel"},{$set:{address:null}});
db.userList.find();
1.3大于小于
<, <=, >, >=
这个操作符也是很常用的,格式如下
db.collection.find({ "field" : { $gt: value } } );
// 大于:field > value
db.collection.find({ "field" : { $lt: value } } );
// 小于:field < value
db.collection.find({ "field" : { $gte: value } } );
// 大于等于:field >= value
db.collection.find({ "field" : { $lte: value } } );
// 小于等于:field <= value
示例:查询年龄大于等于32岁的用户记录
db.userList.find({"age":{$gt:32}});
1.4 不等于
不等于使用
$ne
操作符。
示例:查询age
字段不为“32
”的文档
db.userList.find({age:{$ne:32}});
1.5判断字段是否存在
判断字段是否存在使用
$exists
操作符。
示例:
- 查询所有含有address字符的文档。
- 查询所有不含有address字符的文档。
#查询所有含有address字符的文档。
db.userList.find({address:{$exists:false}});
#查询所有不含有address字符的文档。
db.userList.find({address:{$exists:true}});
1.6 包含与不包含
包含使用
$in
操作符。
- 示例:查询
userList
集合中age
字段包含32,88
的文档
db.userList.find({age:{$in:[32,88]}});
- 示例:查询
userList
集合中age
字段不包含32,88
的文档
1.7 统计记录条数
统计记录条件使用
count()
方法。
- 示例:查询
userList
集合的文档条数。
db.userList.count();
- 示例:查询
userList
集合中age
字段小于等于33
的文档条数。
db.userList.count({age:{$lte:33}});
1.8 条件连接–并且
我们如果需要查询同时满足两个以上条件,需要使用
$and
操作符将条件进行关联。(相当于SQL的and)
格式为:$and:[ { },{ },{ } ]
- 示例:查询
userList
集合中age
大于等于33
并且age
小于100
的文档
db.userList.find({$and:[{age:{$gte:33}},{age:{$lt:100}}]});
1.9 条件连接–或者
如果两个以上条件之间是或者的关系,我们使用
$or
操作符进行关联,与前面$and
的使用方式相同
格式为:$or:[ { },{ },{ } ]
- 示例:查询
userList
集合中address
为shenzhen
,或者age
小于33 的文档记录
db.userList.find({$or:[{address:"shenzhen"},{age:{$lt:33}}]});
二、Java 连接 MongoDB
2.1 创建工程并连接数据库
(1) 启动mongo服务器:
服务端窗口
./mongod --bind_ip 192.168.188.180
#再复制一个窗口作为客户端窗口
mongo 192.168.188.180
(2) 准备数据:
use mydb;
db.userList.save({"id":1001,"name":"Daniel","age":22,"address":"shanghai"});
db.userList.find();
(3)创建maven工程
mongoDBDemo
,引入依赖。
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver</artifactId>
<version>3.4.1</version>
</dependency>
注意,默认情况下
mongodb
监听127.0.0.1
ip,启动时候需要制定外部ip,才能外部链接
./mongod --bind_ip 192.168.188.180
别忘了打开端口27017防火墙
firewall-cmd --add-port=27017/tcp --permanent
firewall-cmd --reload
(4)连接数据库
有密码和无密码:
@Test//连接数据库
public void test1(){
try{
// 连接到 mongodb 服务
MongoClient mongoClient = new MongoClient( "192.168.188.180" , 27017 );
// 连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("mydb");
System.out.println("Connect to database successfully");
}catch(Exception e){
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
}
}
//上面实例中 Mongo 数据库无需用户名密码验证。如果你的 Mongo 需要验证用户名及密码,可以使用以下代码
@Test
public void test2(){
try {
//连接到MongoDB服务 如果是远程连接可以替换“localhost”为服务器所在IP地址
//ServerAddress()两个参数分别为 服务器地址 和 端口
ServerAddress serverAddress = new ServerAddress("192.168.188.180",27017);
List<ServerAddress> addrs = new ArrayList<ServerAddress>();
addrs.add(serverAddress);
//MongoCredential.createScramSha1Credential()三个参数分别为 用户名 数据库名称 密码
MongoCredential credential = MongoCredential.createScramSha1Credential("root", "mydb", "root123".toCharArray());
List<MongoCredential> credentials = new ArrayList<MongoCredential>();
credentials.add(credential);
//通过连接认证获取MongoDB连接
MongoClient mongoClient = new MongoClient(addrs,credentials);
//连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("mydbs");
System.out.println("Connect to database successfully");
} catch (Exception e) {
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
}
}
测试效果:
2.2 创建集合
我们可以使用
com.mongodb.client.MongoDatabase
类中的createCollection()
来创建集合
代码片段如下:
@Test //创建集合
public void test3(){
try{
// 连接到 mongodb 服务
MongoClient mongoClient = new MongoClient( "192.168.188.180" , 27017 );
// 连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("mydb");
System.out.println("Connect to database successfully");
mongoDatabase.createCollection("userList");
System.out.println("集合创建成功");
}catch(Exception e){
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
}
}
测试效果:
2.3 获取集合
我们可以使用
com.mongodb.client.MongoDatabase
类的getCollection()
,find()
方法来获取一个集合
代码片段如下:
@Test //获取集合
public void test4(){
try{
// 连接到 mongodb 服务
MongoClient mongoClient = new MongoClient( "192.168.188.180" , 27017 );
// 连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("mydb");
System.out.println("Connect to database successfully");
MongoCollection<Document> collection = mongoDatabase.getCollection("userList");
System.out.println("集合 userList 选择成功");
FindIterable<Document> list = collection.find();
for( Document doc: list){//遍历集合中的文档输出数据
// System.out.println("id:"+ doc.getInteger("id") );
System.out.println("name:"+ doc.getString("name") );
System.out.println("age:"+ doc.getDouble("age") );//默认为浮点型
System.out.println("address:"+ doc.getString("address") );
System.out.println("--------------------------");
}
}catch(Exception e){
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
}
}
测试效果如下:
2.4 插入文档
我们可以使用
com.mongodb.client.MongoCollection
类的insertMany()
方法来插入一个文档
代码片段如下:
@Test //插入集合
public void test5(){
try{
// 连接到 mongodb 服务
MongoClient mongoClient = new MongoClient( "192.168.188.180" , 27017 );
// 连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("mydb");
MongoCollection<Document> collection = mongoDatabase.getCollection("userList");
//插入文档
/**
* 1. 创建文档 org.bson.Document 参数为key-value的格式
* 2. 创建文档集合List<Document>
* 3. 将文档集合插入数据库集合中 mongoCollection.insertMany(List<Document>) 插入单个文档可以用 mongoCollection.insertOne(Document)
* */
Map<String, Object> map=new HashMap();
map.put("name", "铁扇公主");
map.put("age", "22");
map.put("address", "芭蕉洞");
Document doc=new Document(map);
collection.insertOne(doc);//插入一条记录
//collection.insertMany(doc);//一次性插入多条文档
}catch(Exception e){
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
}
}
测试运行查看数据库
2.5 更新文档
你可以使用
com.mongodb.client.MongoCollection
类中的updateMany()
方法来更新集合中的文档。
updateMany
方法用于修改符合条件的所有记录updateOne
方法用于修改符合条件的第一条记录
代码片段如下:
@Test //更新文档
public void test(){
try{
// 连接到 mongodb 服务
MongoClient mongoClient = new MongoClient( "192.168.188.180" , 27017 );
// 连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("mydb");
MongoCollection<Document> collection = mongoDatabase.getCollection("userList");
//更新文档 将文档中likes=100的文档修改为likes=200
collection.updateMany(Filters.eq("name", "Daniel"), new Document("$set",new Document("age",44)));
//检索查看结果
FindIterable<Document> findIterable = collection.find();
MongoCursor<Document> mongoCursor = findIterable.iterator();
while(mongoCursor.hasNext()){
System.out.println(mongoCursor.next());
}
System.out.println("更新成功");
}catch(Exception e){
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
}
}
测试效果如下:
2.6 删除第一个文档
要删除集合中的第一个文档,首先你需要使用
com.mongodb.DBCollection类中的 findOne()
方法来获取第一个文档,然后使用remove
方法删除。
代码片段如下:
@Test //删除文档
public void test6(){
try{
// 连接到 mongodb 服务
MongoClient mongoClient = new MongoClient( "192.168.188.180" , 27017 );
// 连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("mydb");
MongoCollection<Document> collection = mongoDatabase.getCollection("userList");
//删除符合条件的第一个文档
collection.deleteOne(Filters.eq("id", 1003));
//删除所有符合条件的文档
collection.deleteMany (Filters.eq("id", 1003));
System.out.println("删除成功");
//检索查看结果
FindIterable<Document> findIterable = collection.find();
MongoCursor<Document> mongoCursor = findIterable.iterator();
while(mongoCursor.hasNext()){
System.out.println(mongoCursor.next());
}
}catch(Exception e){
System.out.println("删除失败");
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
}
}
测试效果如下:
三、MongoDB连接池
3.1 代码实现
MongoClient 被设计为线程安全的类,也就是我们在使用该类时不需要考虑并发的情况,这样我们可以考虑把MongoClient 做成一个静态变量,为所有线程公用,不必每次都销毁。这样可以极大提高执行效率。实际上,这是MongoDB提供的内置的连接池来实现的。
1.首先我们先创建一个“
管理类
”MongoManagerUtils
,相当于我们原来的BaseDao
package com.gansu.utils;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoDatabase;
public class MongoManagerUtils {
private static MongoClient mongoClient=null;
//对mongoClient初始化
private static void init(){
mongoClient=new MongoClient("192.168.188.180" , 27017);
}
public static MongoDatabase getDatabase(){
if(mongoClient==null){
init();
}
return mongoClient.getDatabase("mydb");
}
}
- 然后我们创建一个
UserDao
package com.gansu.dao;
import com.gansu.utils.MongoManagerUtils;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
public class UserDao {
public void save(String name, double age, String address){
MongoDatabase database = MongoManagerUtils.getDatabase();
MongoCollection<Document> collection = database.getCollection("userList");
Document docment=new Document();
docment.put("name", name);
docment.put("age", age);
docment.put("address", address);
collection.insertOne(docment);
}
}
- 我们现在创建
UserTest
做个测试,循环插入1万条数据,看看执行时间是多长时间
package com.gansu.dao;
import com.gansu.dao.UserDao;
import java.util.Date;
public class UserTest {
public static void main(String[] args) {
long startTime = new Date().getTime();//开始时间
UserDao userDao=new UserDao();
for(int i=0;i<10000;i++){
userDao.save("测试"+i, 99,"香港"+i);
}
long endTime = new Date().getTime();//完成时间
System.out.println("完成时间:"+(endTime-startTime)+"毫秒");
}
}
测试运行得是:
经过测试:所用毫秒数为
9017ms
3.2 参数设置
我们在刚才的代码基础上进行连接池参数的设置
修改MongoManagerUtils
的init
方法
//对mongoClient初始化
private static void init(){
//连接池选项
MongoClientOptions.Builder builder = new MongoClientOptions.Builder();//选项构建者
builder.connectTimeout(5000);//设置连接超时时间
builder.socketTimeout(5000);//读取数据的超时时间
builder.connectionsPerHost(30);//每个地址最大请求数
builder.writeConcern(WriteConcern.NORMAL);//写入策略,仅抛出网络异常
MongoClientOptions options = builder.build();
mongoClient=new MongoClient("192.168.188.180" , 27017);
}
再次进行测试:
所用的毫秒8861
四、综合案例-《网站点击日志分析组件》
此案例后期会更新详测。。。。。。
4.1 需求分析
《花生二手车》交易网站日访问IP高达2万+ ,每秒点击频率在2000次左右。为了能够对访问用户的行为做进一步的分析,产品部提出需求,用户每次点击浏览二手车都要记录该用户ID、访问IP、访问时间、点击车型、点击商品ID、价格等信息。
4.2 数据库设计
字段名称 | 字段类型 | 字段含义 |
---|---|---|
userid | 字符 | 用户ID |
ip | 字符 | 访问IP |
browseTime | 时间 | 访问时间 |
model | 字符 | 点击车型 |
goodsid | 字符 | 点击商品ID |
price | 数值 | 价格 |
remark | 字符 | 备注 |
4.3 日志写入
(1)创建 maven 工程
sitelog
(2) 在pom.xml中引入依赖。
(3) 在src/main/resources 添加配置文件
sitelog.properties
host=192.168.188.180
port=27017
这个配置文件用于配置主机地址和端口
(4)创建包
com.gansu.sitelog
,建立Config
类,用于读取配置文件
package com.gansu.sitelog;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class Config {
static{
try {
Properties p=new Properties();
InputStream input=Config.class.getResourceAsStream("/sitelog.propertis");
p.load(input);
host=p.getProperty("host");
port=Integer.parseInt( p.getProperty("port"));
input.close();
} catch (IOException e) {
e.printStackTrace();
}//加载
}
private static String host;//主机地址
private static int port;//端口
public static String getHost() {
return host;
}
public static int getPort() {
return port;
}
}
(5)创建管理类
MongoManager
package com.gansu.utils;
import com.gansu.sitelog.Config;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.ServerAddress;
import com.mongodb.WriteConcern;
import com.mongodb.client.MongoDatabase;
public class MongoManager {
private static MongoClient mongoClient=null;
//初始化
private static void init(){
//创建一个选项构造器
MongoClientOptions.Builder builder = new MongoClientOptions.Builder();
builder.connectTimeout(5000);//设置连接超时时间
builder.socketTimeout(5000);//读取数据的超时时间
builder.connectionsPerHost(30);//设置每个地址最大连接数
builder.writeConcern(WriteConcern.NORMAL);//设置写入策略 ,只有网络异常才会抛出
//得到选项封装
MongoClientOptions options = builder.build();
mongoClient=new MongoClient(new ServerAddress(Config.getHost(), Config.getPort()),options);
}
public static MongoDatabase getDatabase(){
if(mongoClient==null){
init();
}
return mongoClient.getDatabase("mydb");
}
}
(6)日志工具类
package com.gansu.utils;
import com.mongodb.BasicDBObject;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import java.util.Map;
public class SiteLogUtil {
/**
* 写入日志
* @param logname 日志名称
* @param map 日志数据
*/
public static void save(String logname, Map<String, Object> map){
MongoDatabase database = MongoManager.getDatabase();
MongoCollection<Document> collection = database.getCollection(logname);
Document doc=new Document(map);
collection.insertOne(doc);
}
}
(7)编写测试代码
SiteTest
package com.gansu;
import com.gansu.utils.SiteLogUtil;
import org.junit.Test;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class SiteTest {
@Test
public void test1(){
Map map=new HashMap();
map.put("userid", "8888");
map.put("ip", "39.107.217.4");//39.107.217.4:443
map.put("browseTime", new Date());
map.put("model", "大众");
map.put("goodsid", "123123");
map.put("price", 15.3);
map.put("remark", "八成新,贱卖了");
SiteLogUtil.save("browseLog", map);//存入日志
}
}
4.4 日志查询
4.4.1 条件查询
(1)在
SiteLogUtil
类中添加方法
/**
* 按条件查询
* @param logName
* @param map
* @return
*/
public static FindIterable<Document> list(String logName, Map<String, Object> map){
MongoDatabase database = MongoManager.getDatabase();
MongoCollection<Document> collection = database.getCollection(logName);
BasicDBObject bson=new BasicDBObject(map);//构建查询条件
return collection.find(bson);
}
(2)编写测试代码
@Test
public void test2(){
Map<String, Object> map =new HashMap();
map.put("userid", "8888");
FindIterable<Document> list = SiteLogUtil.list("browseLog", map);
String json = JSON.serialize(list);
System.out.println(json);
}
4.4.2 分页查询
(1)在
SiteLogUtil
类中添加方法
/**
* 分页查询日志
* @param logName 日志名称
* @param map 条件
* @param pageIndex 页码
* @param pageSize 页大小
* @return
*/
public static Map<String,Object> listPage(String logName,Map<String, Object> map,int pageIndex,int pageSize){
MongoDatabase database = MongoManager.getDatabase();
MongoCollection<Document> collection = database.getCollection(logName);
BasicDBObject bson=new BasicDBObject(map);//构建查询条件
FindIterable<Document> find = collection.find(bson);
int skip= (pageIndex-1)*pageSize;
find.skip( skip);//跳过记录数
find.limit(pageSize);//一页查询记录数
//{ total:x,rows:[] }
long count = collection.count(bson);
Map<String,Object> m=new HashMap();
m.put("total", count);
m.put("rows", find);
return m;
}
(2)添加测试数据
编写测试代码
@Test
public void test3(){
for(int i=0;i<1000;i++){
Map<String, Object> map=new HashMap();
map.put("userid", "900"+i);//用户ID
map.put("ip", "121.211.112.212");
map.put("browseTime", new Date());//浏览时间
map.put("model", "大众"+i);//型号
map.put("goodsid", "123456");//商品ID
map.put("price", 11.8);//价格
map.put("remark", "八成新,快来买吧");
SiteLogUtil.save("browseLog", map);
}
}
@Test
public void test4(){
Map<String, Object> map=new HashMap();
map.put("goodsid", "123456");
Map<String, Object> m = SiteLogUtil.listPage("browseLog", map, 2, 10);
String json = JSON.serialize(m);
System.out.println(json);
}
使用Maven 的package命令进行打包。
创建WEB工程,引入jar包,调用此方法即可实现日志查询。代码待后期更新上传。