MongoDB实战 – 作者:是你的小凉凉呀

最近进行MongoDB开发,虽然需求比较简单,但是涉及较多的细节使用。加之不够熟悉 就使用了各种方法达到目标。

## 1.简介

MongoDB是一个基于分布式文件存储的数据库,一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。

MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。支持比较丰富和复杂的数据类型。

MongoDB已经在多个站点部署,其主要场景如下:

1)网站实时数据处理。它非常适合实时的插入、更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。

2)缓存。由于性能很高,它适合作为信息基础设施的缓存层。在系统重启之后,由它搭建的持久化缓存层可以避免下层的数据源过载。

3)高伸缩性的场景。非常适合由数十或数百台服务器组成的数据库,它的路线图中已经包含对MapReduce引擎的内置支持。

不适用的场景如下:

1)要求高度事务性的系统。

2)传统的商业智能应用。

3)复杂的跨文档(表)级联查询。

## 2.使用

### 连接和认证——方式一( MongoClient )

使用mongoclient的方式。MongoClient是线程安全的,可以在多程程环境中共享同一个MongoClient。通常来说,一个应用程序中,只需要生成一个全局的MongoClient实例,然后在程序的其他地方使用这个实例即可。

直接连接:

MongoClient mongoClient = new MongoClient(“localhost”, 27017); // 获取链接
MongoDatabase database = mongoClient.getDatabase(“mydb”); // 获取数据库

认证与连接:

MongoClientOptions.Builder builder = MongoClientOptions.builder(); //可以通过builder做各种详细配置 MongoClientOptions myOptions = builder.build();

ArrayList<ServerAddress> serverAddressList = new ArrayList();

ServerAddress record = new ServerAddress(“localhost”, 27017); //IP、端口

serverAddressList.add(record); //用户名、默认库名、密码

MongoCredential credential = MongoCredential.createCredential(“账号”, “默认库名”, “密码”.toCharArray());

MongoClient mongoClient = new MongoClient(serverAddressList, credential, myOptions);

### 连接和认证——方式二( MongoClientURI)

直接使用MongoClientURI完成MongoDB的认证,它代表了一个URI对象。MongoClientURI的构造函数接受一个String类型的字符串,这个字符串的格式如下:

String sURI = String.format(
“mongodb://%s:%s@%s:%d/%s”, ”用户名“, ”密码“, ”localhost“, 27017, ”数据库”);
MongoClientURI uri = new MongoClientURI(sURI);

MongoClient mongoClient = new MongoClient(uri);

DB db = mongoClient.getDB(“数据库”);

MongoClientOptions.Builder mongoBuilder = new MongoClientOptions.Builder(); mongoBuilder.maxWaitTime(1000*60*3);

mongoBuilder.connectTimeout(60*1000*3); //与数据库建立连接的timeout设置为1分钟 mongoBuilder.minConnectionsPerHost(1);

MongoClientURI mongoClientURI = new MongoClientURI(“mongodb://root:root@localhost:27017/数据库”,mongoBuilder);

SimpleMongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(mongoClientURI); MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory);

### 连接和认证——方式三( MongoTemplate)

public MongoClient mongoClient() {

MongoCredential credential = MongoCredential.createCredential(“用户”, “数据库”, “password”);
return MongoClients.create(
MongoClientSettings.builder()
.applyToClusterSettings(builder ->
builder.applyConnectionString(new ConnectionString(serverList)))
.credential(credential)
.applicationName(“应用”)
.readConcern(ReadConcern.MAJORITY)
.readPreference(ReadPreference.primaryPreferred())
.writeConcern(WriteConcern.MAJORITY)
.applyToConnectionPoolSettings(builder -> {
builder
.maxWaitTime(1, TimeUnit.SECONDS)
.maxSize(10);
})
.applyToSocketSettings(builder -> builder
.connectTimeout(5, TimeUnit.SECONDS)
.readTimeout(5, TimeUnit.SECONDS))
.build());
}

public MongoTemplate mongoTemplate() {
return new MongoTemplate(mongoClient(), “数据库”);
}

### CRUD——方式一

基于注解的方式:

1.实体上使用 @Document(collection = ”UserDO”)
2.继承MongoRepository,简单的增删改查无需实现,可直接使用

@Repository
public interface UserExtRepository extends MongoRepository<UserDO, String> {  
List<UserDO> findById(String id);
}

xxRepository.insert(UserDO);

xxRepository. findBy(”11”);

Repositry接口
基础的 Repository提供了最基本的数据访问功能,其几个子接口则扩展了一些功能。它们的继承关系如下:

**Repository**:仅仅是一个标识,表明任何继承它的均为仓库接口类

**CrudRepository**:继承Repository,实现了一组CRUD相关的方法

**PagingAndSortingRepository**:继承CrudRepository,实现了一组分页排序相关的方法

**JpaRepository**:继承PagingAndSortingRepository,实现一组JPA规范相关的方法

自定义的XxxxRepository需要继承 JpaRepository,这样的XxxxRepository接口就具备了通用的数据访问控制层的能力。

**JpaSpecificationExecutor**:不属于Repository体系,实现一组JPACriteria查询相关的方法

### CRUD——方式二

增:

MongoCollection<Document> collection = mongo.getDb(“database”).getCollection(“CollectionName”);
Document document = Document.parse(JSONObject.toJSONString(userDO));
collection.insertOne(document);

collection.insertMany(document);

删:

MongoCollection<Document> collection = mongo.getDb(database).getCollection(“collection”);
BasicDBObject queryObject = new BasicDBObject(”id“,”1111“);
collection.deleteOne(queryObject);

collection.deleteMany(queryObject);

改:

MongoCollection<Document> collection = mongo.getDb(“database”).getCollection(“collection”);
BasicDBObject queryObject = new BasicDBObject(“id”,“1111”);
BasicDBObject updateNewOneSql = new BasicDBObject(“$set”, new BasicDBObject(“name”, “tom”));
collection.updateOne(queryObject, updateNewOneSql);

collection. updateMany();

collection. findOneAndUpdate();

查:

MongoCollection<Document> collection = mongo.getDb(database).getCollection(“collection”);
BasicDBObject queryObject = new BasicDBObject(”id“,”1111“);
FindIterable<Document> documents = collection.find(queryObject);

other:

collection.aggregate();//聚合索引

collection.countDocuments();//统计

collection.createIndex();   collection. dropIndex();  //增加删除索引

collection.createIndexs();   collection. dropIndexs(); //批量增加删除索引

collection.replaceOne();//替换文档

collection.distinct();//返回具有指定字段不同值的文档(去除指定字段的重复数据)

collection.bulkWrite();//批量写入

collection.dataSize();//返回集合大小

collection.drop(); //删除集合

聚合查询:

BasicDBObject query= new BasicDBObject();

BasicDBObject[] array = { new BasicDBObject(“time”, new BasicDBObject(“$gte”, “2018-09-12”)),new BasicDBObject(“time”, new BasicDBObject(“$lte”,”2018-12-25″))};

query.append(“$and”, array);

BasicDBObject match = new BasicDBObject(“$match”, query); // match(相当于 WHERE 或者 HAVING )

BasicDBObject group = new BasicDBObject(“$group”, new BasicDBObject(“_id”, “$subject”) //group(相当于 GROUP BY)

.append(“count”, new BasicDBObject(“$sum”, 1)));

BasicDBObject sort = new BasicDBObject(“$sort”, new BasicDBObject(“count”, -1));//1:正序,-1倒序

BasicDBObject limit = new BasicDBObject(“$limit”, pageSize); //limt(只要前多少条数据,分页时使用)

BasicDBObject skip = new BasicDBObject(“$skip”, xx); //skip(跳过前面多少条数据,分页时使用)

List<DBObject> queryList = new ArrayList<>(); //queryList集合里的顺序不能乱,否则会报错。

queryList .add(match);

queryList .add(group);

queryList .add(sort);

queryList .add(skip);

queryList .add(limit);

AggregateIterable<Document> iterable = mongoClient.mongoClient.getDatabase(dbName).getCollection(gatherName).aggregate(queryList );

### CRUD——分页查询

方式一:使用limit和skip进行分页find().skip((pageNum-1)*pageSize).sort().limit(pageSize)

方式二:通过原生的方法实现条件查询、分页和排序

方式三:通过实现Pageable接口等方式做自定义实现

find(索引).projection(查询字段).sort().limit()

1617875516_606ed23c170a7ccee929e.png!small?1617875516420

本文作者:琉璃@涂鸦智能安全团队

漏洞悬赏计划:涂鸦智能安全响应中心(https://src.tuya.com)欢迎白帽子来探索。

招聘内推计划:涵盖安全开发、安全测试、代码审计、安全合规等所有方面的岗位,简历投递[email protected],请注明来源。

来源:freebuf.com 2021-04-08 17:53:59 by: 是你的小凉凉呀

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论