三十、MongoDB(2)

一、高级查询

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集合中addressshenzhen,或者age小于33 的文档记录
 db.userList.find({$or:[{address:"shenzhen"},{age:{$lt:33}}]});

在这里插入图片描述

二、Java 连接 MongoDB

2.1 创建工程并连接数据库

CRUD 参考菜鸟教程 MongoDB Java

(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.1ip,启动时候需要制定外部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");
    }
}
  1. 然后我们创建一个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);
    }
}
  1. 我们现在创建 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 参数设置

我们在刚才的代码基础上进行连接池参数的设置

修改MongoManagerUtilsinit方法

在这里插入图片描述

//对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包,调用此方法即可实现日志查询。代码待后期更新上传。

文章源码

  • 17
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Daniel521-Spark

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值