java操作mongodb详解

本文详细介绍了在Java项目中使用MongoDB的操作,包括创建客户端、自定义解码器、批量写入和更新数据、复杂查询(如自定义条件和多表lookup)、以及使用命令行工具进行数据操作。此外,还推荐了可视化工具MongoDBCompass和SpringBoot项目的配置示例。
摘要由CSDN通过智能技术生成

前言
一切操作都应该以官方文档为准,mongodb官网文档地址: https://www.mongodb.com/docs/ ,网上关于java操作mongodb的文章偏少,而且有些乱。这篇文章是在项目中使用mongodb后的一些总结,希望能帮到大家。

1.创建mongodb客户端(这里注册了自定义解码器,方便直接存java对象)

String linkUrl = "mongodb://" + url;
if (hasAuth) { //需要用户名密码用下面的方式拼接url
	linkUrl = "mongodb://" + username + ":" + password + "@" + url + "/" + databaseName;
}
CodecRegistry pojoCodecRegistry = CodecRegistries.fromRegistries(
		MongoClientSettings.getDefaultCodecRegistry(),
		CodecRegistries.fromProviders(PojoCodecProvider.builder().automatic(true).build()));

MongoClientSettings build = MongoClientSettings.builder()
		.codecRegistry(pojoCodecRegistry)
		.applyConnectionString(new ConnectionString(linkUrl))
		.build();
 MongoClient client = MongoClients.create(build);

2.批量写入对象数据

  public static void write(MongoClient client, String databaseName, String collectionName, List<?> dataList) {
        if (dataList != null && dataList.size() != 0) {
            MongoDatabase database = client.getDatabase(databaseName);
            MongoCollection<Document> collection = database.getCollection(collectionName);
            List<WriteModel<Document>> writes = new ArrayList();
            Iterator var7 = dataList.iterator();

            while(var7.hasNext()) {
                Object data = var7.next();
                Map<String, Object> dataMap = ObjectToMapUtil.objectToMap(data);
                writes.add(new InsertOneModel(new Document(dataMap)));
            }

            collection.bulkWrite(writes);
        }
    }
	
	 public static Map<String, Object> objectToMap(Object obj) {
        Map<String, Object> map = new HashMap();
        try {
            Class<?> clazz = obj.getClass();
            for (Field field : clazz.getDeclaredFields()) {
                field.setAccessible(true);
                map.put(field.getName(), field.get(obj));
            }
        }catch (Exception e){
            log.info("ObjectToMapUtil.objectToMap 实体类转换成Map失败={}", JSON.toJSONString(e.getMessage()));
            e.printStackTrace();
        }
        return map;
    }

3.批量更新数据

private void batchUpdateData(MongoCollection<Document> collection, List<POJO> list) {

    if (CollectionUtil.isEmpty(list)) {
        return;
    }
    List<String> ids = list.stream().map(POJO::get_id).collect(Collectors.toList());
	 List<WriteModel<Document>> writes = new ArrayList();
    for (int i = 0; i < list.size(); i++) {
        Object data = list.get(i);
        String id = ids.get(i);
        Map<String, Object> dataMap = ObjectToMapUtil.objectToMap(data);
        UpdateOneModel updateOneModel = new UpdateOneModel(Filters.eq("_id", id), new Document("$set", new Document(dataMap)), (new UpdateOptions()).upsert(true));
        writes.add(updateOneModel);
    }
    collection.bulkWrite(writes);
}

4.查询

4.1.自定义条件封装,二维数组

private Document buildReportQuery(BasicPageBO pageBO) {
        Document query = new Document();
        List<List<Condition>> conditions = pageBO.getConditions();
        if (CollectionUtil.isEmpty(conditions)) {
            return query;
        }

        query = MongoOperateUtil.buildConditions(conditions);
        return query;
    }
	
	//BasicPageBO是一个灵活的参数对象,里面有分页信息,非常好用
	
	//条件参数对象
	public static class Condition implements Serializable {
		@ApiModelProperty("字段名")
		private String field;
		@ApiModelProperty("操作符,gt,gte,eq等")
		private String operator;
		@ApiModelProperty("值")
		private String value;
		@ApiModelProperty("逻辑条件,and、or等")
		private String logic;
	}
	
	 public static Document strEq(String field, String value) {
        return  new Document(field, value);
    }

    public static Document buildBson(BasicPageBO.Condition condition) {
        String operator = condition.getOperator();
        switch (operator) {
            case "eq" :
                return MongoOperateUtil.strEq(condition.getField(), condition.getValue());
            case "ne" :
                return MongoOperateUtil.strNe(condition.getField(), condition.getValue());
            case "like" :
                return MongoOperateUtil.like(condition.getField(), condition.getValue());
            case "startWith" :
                return MongoOperateUtil.leftLike(condition.getField(), condition.getValue());
            case "endWith" :
                return MongoOperateUtil.rightLike(condition.getField(), condition.getValue());
            case "in" :
                return MongoOperateUtil.strIn(condition.getField(), condition.getValue());
            case "nin" :
                return MongoOperateUtil.strNin(condition.getField(), condition.getValue());
            case "isNull" :
                return MongoOperateUtil.isNull(condition.getField(), null);
            default: {

                return null;
            }

        }
    }

    private static Document strNe(String field, String value) {
        return new Document(field, new Document("$ne", value));
    }

    private static Document isNull(String field, String value) {
        return new Document(field, value);
    }

    public static Document buildConditions(List<List<BasicPageBO.Condition>> conditionAll){
        Document totalBson = null;
        for (int i = 0; i < conditionAll.size(); i++) {
            List<BasicPageBO.Condition> conditions = conditionAll.get(i);

            Document oneBson = null;
            String twoLogic = conditions.get(0).getLogic();

            for (int j = 0; j < conditions.size(); j++) {
                BasicPageBO.Condition condition = conditions.get(j);
                String logic = condition.getLogic();
                //加上前缀
                condition.setField("dataMap." + condition.getField());
                //单个构建
                Document bson = MongoOperateUtil.buildBson(condition);
                if (0 == j) {
                    oneBson = bson;
                } else {
                    oneBson = MongoOperateUtil.conditionOn(oneBson, bson, logic);
                }
            }

            if (0 == i) {
                totalBson = oneBson;
            } else {
                totalBson = MongoOperateUtil.conditionOn(totalBson, oneBson, twoLogic);
            }
        }

        return totalBson;
    }

    public static Document conditionOn(Document first, Document two, String logic) {
        BasicDBList list = new BasicDBList();
        list.add(first);
        list.add(two);
        if ("and".equals(logic)) {
            return new Document("$and", list);
        } else if("or".equals(logic)) {
            return new Document("$or", list);
        }
        return null;
    }

    public static Document strIn(String field, String value) {
        String[] valueArr = value.split(",");
        List<String> vList = Arrays.asList(valueArr);
        String operate = "$in";
        BasicDBList vBasics = new BasicDBList();
        vBasics.addAll(vList);

        return new Document(field, new Document(operate, vBasics));
    }

    public static Document strNin(String field, String value) {
        String[] valueArr = value.split(",");
        List<String> vList = Arrays.asList(valueArr);
        String operate = "$nin";
        BasicDBList vBasics = new BasicDBList();
        vBasics.addAll(vList);

        return new Document(field, new Document(operate, vBasics));
    }


    public static Document like(String field, String value) {
        Document dbo = new Document();
        Pattern pattern = Pattern.compile("^.*" + value+ ".*$", Pattern.CASE_INSENSITIVE);
        dbo.put(field, pattern);
        return dbo;
    }

    public static Document leftLike(String field, String value) {
        Document dbo = new Document();
        Pattern pattern = Pattern.compile("^" + Pattern.quote(value) + ".*", Pattern.CASE_INSENSITIVE);
        dbo.put(field, pattern);
        return dbo;
    }

    public static Document rightLike(String field, String value) {
        Document dbo = new Document();
        Pattern pattern = Pattern.compile(".*" + Pattern.quote(value) + "$", Pattern.CASE_INSENSITIVE);
        dbo.put(field, pattern);
        return dbo;
    }

4.2 单表查询

Document condition = new Document();
	condition.put(k,v)//加各种条件
   计数 db.getCollection(表名).countDocuments(condition)
   分页查询 db.getCollection(表名).find(condition).skip(skip).limit(pageSize);

4.3 多表lookup关联查询(大数据量时,已经放弃,分页查询求count时性能极慢(30w数据,耗时30秒左右))

4.3.1 执行的各个阶段
l o o k u p − > lookup-> lookup>match-> g r o u p − > group-> group>sort-> u n w i n d − > unwind-> unwind>project-> s k i p − > skip-> skip>limit
leftjoin用到$unwind preserveNullAndEmptyArrays: true

	4.3.2 如下是一个案例:
	int current = (int) pageBO.getCurrent();
        int pageSize = (int) pageBO.getSize();
        int skip = pageSize * (current - 1);

        //以key(某个字段)关联
        String joinField = "key";
        //注意,这个字段名需要与返回数据对象中的(关联对象)属性名称对应,不然json解析不出数据
        String tableAlias = "linkDto";

        // 联合查询条件
        List<Bson> aggregationList = new LinkedList<Bson>();

         //主表查询条件
        Bson matchFilter = Aggregates.match(match);
        aggregationList.add(matchFilter);

         //从表名、主表连接字段、从表连接字段、别名
        aggregationList.add(
                Aggregates.lookup(param.getTableId(), joinField, joinField, tableAlias)
        );

       
        BasicDBObject bson = new BasicDBObject();
        bson.put(statusKey, param.getStatus);


		aggregationList.add(
				Aggregates.unwind("$linkDto", new UnwindOptions().preserveNullAndEmptyArrays(true))
		);
       
        aggregationList.add(
                Aggregates.match(bson)
        );


		List<Bson> countBson = new ArrayList<>(aggregationList);
        countBson.add(
                Aggregates.group("_id", new BsonField("count", new BasicDBObject("$sum", 1)))
        );

        //分组聚会统计数量
        AggregateIterable<Document> countAgg = util.getDb().getCollection(表名).aggregate(countBson).batchSize(1);

        long total = 0;
        Document first = countAgg.first();
        if (Objects.nonNull(first) && Objects.nonNull(first.get("count"))) {
            total = (long) (Integer) first.get("count");
        }


        aggregationList.add(Aggregates.skip(skip));
        aggregationList.add(Aggregates.limit(pageSize));

        AggregateIterable<Document> labelList = util.getDb().getCollection(表名).aggregate(aggregationList);

        //提取和转换结果集
        for (Document dr : labelList) {
            dr.toJson();
			//todo .....
        }
        PageDto<POJOView> pageBean = new PageDto<>();
        pageBean.setTotal(total);

        pageBean.setRecords(results);
        pageBean.setCurrent(current);
        pageBean.setSize(pageSize);
		

## 5.命令行相关查询(直接放到navicat上执行)

    例子1,总数
	

```javascript
  db.getCollection("主表名").aggregate([
	  {
		$lookup: {
		  from: "从表名", // 关联的集合名称
		  localField: "key", // 本地字段,主表关联字段,建索引也没有卵用 集合中用于关联的字段
		  foreignField: "key", // 外部字段,从表关联字段 集合中用于关联的字段, 意思是主表key=从表key,若不是相等,可以用管线的形式(构建其他条件,最后别用,真是难用)
		  as: "report" // 关联结果存放的字段名
		}
	  },
	  {
		$unwind: {
		  path: "$report",
		  preserveNullAndEmptyArrays: true // 保留没有匹配的订单文档
		}
	  },
	  { 
			  $match : { 
			   "report.字段a":"xxx",
				$or: [
	  { "report.字段b": "aaa" }
		  ]
					}
	   },
		{
		$group: {
		  _id:null,
		 count:{$sum:1}
		}
	  },
	  {
		$project: {
		  count:1
		}
	  }
	])
	
例子2,关联查询list数据
db.getCollection("主表名").aggregate([
	  {
		$lookup: {
		  from: "从表名", // 关联的集合名称
		  localField: "主表关联key", // 本地字段,orders 集合中用于关联的字段
		  foreignField: "从表关联key", // 外部字段,customers 集合中用于关联的字段
		  as: "report" // 关联结果存放的字段名
		}
	  },
	  {
		$unwind: {
		  path: "$report",
		  preserveNullAndEmptyArrays: true // 保留没有匹配的订单文档
		}
	  },
			{ 
					$match : { 
					  "report.字段a":"xxx",
							$or: [
			{ "report.字段b": "xxxc" }
		  ]
					}
			},
	  {
		$project: {
		  _id: 1,
		  主表字段a:1,
		  主表字段b:1,
		  report: {
			_id: "$report._id",
		    ......
		  }
		}
	  },
			{
		$skip: 0 // 跳过的文档数,用于分页
	  },
	  {
		$limit: 10 // 限制返回的文档数,用于分页
	  }
	])

6.其他

6.1 可视化工具,MongoDB Compass,实用又好用,查看,编辑,导入导出,下载地址
 https://www.mongodb.com/try/download/compass
6.2 navicat可以执行命令,查询数据选择行模式
6.3 springboot项目,打印命令行参数(参考),yml或properties中配置
	logging.level.root debug
	logging.level.org.springframework.data.mongodb.core: debug

6.4分片集群
	分片集群部署
	    https://blog.csdn.net/github_38616039/article/details/134158118
	分配数据创建
		sh.enableSharding("库名")
		db.getCollection(表名).createIndex({ fieldName: 1 })
		sh.shardCollection('库名.表名',{pkValue:1})
		db.adminCommand("flushRouterConfig")
		sh.enableBalancing("库名.表名")
		sh.startBalancer() 
		sh.status({"verbose":1})
		db.表名.getShardDistribution()

7.参考网站

http://www.manongjc.com/detail/33-nlyyuqqbufycepj.html
https://www.mongodb.com/docs/manual/reference/operator/aggregation/count/
https://www.mongodb.com/docs/manual/reference/operator/aggregation/lookup/?_ga=2.167579261.2108825086.1710915715-66292563.1709890069
https://www.jb51.net/program/285486kdm.htm#_lab2_2_5
https://blog.csdn.net/superatom01/article/details/135004991?spm=1001.2014.3001.5506
https://www.knowledgedict.com/tutorial/mongodb-create-index.html

  • 10
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,下面是一个简单的Java程序,演示如何使用MongoDB Java驱动程序进行查询。 首先,您需要使用Maven或Gradle等工具将MongoDB Java驱动程序添加到您的项目中。然后,您需要创建一个MongoClient实例,该实例表示与MongoDB服务器的连接。 ``` MongoClient mongoClient = new MongoClient("localhost", 27017); ``` 接下来,您需要选择一个数据库并创建一个MongoDatabase实例。 ``` MongoDatabase database = mongoClient.getDatabase("myDatabase"); ``` 然后,您可以选择一个集合并创建一个MongoCollection实例。 ``` MongoCollection<Document> collection = database.getCollection("myCollection"); ``` 现在,您可以使用MongoCollection实例执行各种查询。例如,以下代码将查询集合中所有文档的数量。 ``` long count = collection.countDocuments(); System.out.println("Total documents in collection: " + count); ``` 您还可以使用MongoCollection实例执行更复杂的查询。例如,以下代码将查询集合中年龄大于30的所有文档。 ``` Document query = new Document("age", new Document("$gt", 30)); List<Document> results = collection.find(query).into(new ArrayList<>()); for (Document doc : results) { System.out.println(doc.toJson()); } ``` 在上面的代码中,我们使用一个查询文档来指定查询条件,然后使用find()方法执行查询。我们使用into()方法将查询结果转换为一个ArrayList。 以上是一个简单的MongoDB Java查询的例子,您可以根据自己的需求进行修改和扩展。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值