spring:
  mongodb:
    maxSize: 100 # 允许的最大连接数。这些连接在空闲时将保留在池中。一旦池耗尽,任何需要连接的操作都将阻塞等待可用连接 默认: 100
    minSize: 10 # 最小连接数。这些连接在空闲时将保留在池中,并且池将确保它至少包含这个最小数量 默认: 0
    maxConnectionLifeTime: 0 # 池连接可以存活的最长时间。零值表示寿命没有限制。超过其生命周期的池连接将被关闭并在必要时由新连接替换
    maxConnectionIdleTime: 5 # 池连接的最大空闲时间。零值表示对空闲时间没有限制。超过其空闲时间的池连接将被关闭并在必要时由新连接替换
    maxWaitTime: 60000 # 默认最大连接时间120s;
    one:
      uri: mongodb://root:xx.12323@192.168.112.179:27072/${spring.mongodb.one.database}?authSource=admin&authMechanism=SCRAM-SHA-256
      database: hc_test
      # 上方为明确指定某个数据的用户进行连接
      # 也可以使用admin 数据库中的用户进行连接  统一到admin 数据库进行认证
      # admin 用户认证 url 写法: mongodb://账户:密码%40@ip:端口/数据库名?authSource=admin&authMechanism=SCRAM-SHA-1
    two:
      uri: mongodb://root:sx.123@192.168.118.179:27072/${spring.mongodb.two.database}?authSource=admin&authMechanism=SCRAM-SHA-256
      database: nxyxx_qt_test
      # 上方为明确指定某个数据的用户进行连接
      # 也可以使用admin 数据库中的用户进行连接  统一到admin 数据库进行认证
      # admin 用户认证 url 写法: mongodb://账户:密码%40@ip:端口/数据库名?authSource=admin&authMechanism=SCRAM-SHA-1

 

package org.example.config;

import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;


/**
 * @program: sxsoft_operation_admin
 * @ClassName DataSourceConfig
 * @description:monogodb多数据源配置  非关系型数据库
 * @author: 黄涛
 * @create: 2022-10-08 15:41
 * @Version 1.0
 **/
@Configuration
public class MongoDBConfig {

    /**
     * 获取默认数据库属性配置
     * @return
     */
    @Primary
    @Bean(name = "oneMongoProperties")
    @ConfigurationProperties(prefix = "spring.mongodb.one")
    public MongoProperties oneMongoProperties() {
        return new MongoProperties();
    }

    /**
     * 获取第二数据库属性配置
     * @return
     */
    @Bean(name = "twoMongoProperties")
    @ConfigurationProperties(prefix = "spring.mongodb.two")
    public MongoProperties twoMongoProperties() {
        return new MongoProperties();
    }
}
package org.example.config;

import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.SpringDataMongoDB;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;

import java.util.concurrent.TimeUnit;

/**
 * 使用说明:
 * 1、配置属性参数
 * 2、配置模板
 * 3、配置连接池
 */
@Configuration
@EnableMongoRepositories
public class MongoTemplateConfig {

    //region 参数注入
    @Value("${spring.mongodb.maxSize}")
    private int maxSize;
    @Value("${spring.mongodb.minSize}")
    private int minSize;
    @Value("${spring.mongodb.maxConnectionLifeTime}")
    private int maxConnectionLifeTime;
    @Value("${spring.mongodb.maxConnectionIdleTime}")
    private int maxConnectionIdleTime;
    @Value("${spring.mongodb.maxWaitTime}")
    private int maxWaitTime;
    //endregion



    //region 1、属性参数配置

    //默认数据库属性配置
    private final MongoProperties oneMongoProperties;
    //第二数据库属性配置
    private final MongoProperties twoMongoProperties;

    public MongoTemplateConfig(@Qualifier("oneMongoProperties") MongoProperties oneMongoProperties,
                               @Qualifier("twoMongoProperties") MongoProperties twoMongoProperties) {
        this.oneMongoProperties = oneMongoProperties;
        this.twoMongoProperties = twoMongoProperties;
    }

    //endregion


    //region 2、模板配置
    /**
     * @Primary默认数据库模板/第一个数据库模板
     * @return
     */
    @Primary
    @Bean(name = "oneMongotemplate")
    public MongoTemplate oneMongotemplate(@Qualifier("oneMongoDatabaseFactory") MongoDatabaseFactory mongoDatabaseFactory) {
        return  getMongoTemplate(mongoDatabaseFactory);
//        MongoDatabaseFactory mongoDatabaseFactory = new SimpleMongoClientDatabaseFactory(oneMongoProperties.getUri());
//        return new MongoTemplate(mongoDatabaseFactory);
    }



    /**
     * 第二数据库模板
     * @return
     */
    @Bean(name = "twoMongotemplate")
    public MongoTemplate twoMongotemplate(@Qualifier("twoMongoDatabaseFactory") MongoDatabaseFactory mongoDatabaseFactory) {
        return  getMongoTemplate(mongoDatabaseFactory);
    }
    //endregion


    //region 3、连接池配置

    /**
     * 第一数据库连接池配置
     * @return
     */
    @Bean
    @Primary
    public MongoDatabaseFactory oneMongoDatabaseFactory() {
        return getSimpleMongoClientDatabaseFactory(oneMongoProperties);
    }

    /**
     * 第二数据库连接池配置
     * @return
     */
    @Bean
    public MongoDatabaseFactory twoMongoDatabaseFactory() {
        return getSimpleMongoClientDatabaseFactory(twoMongoProperties);
    }


    /**
     * 连接池工厂
     * @param properties
     * @return
     */
    private SimpleMongoClientDatabaseFactory getSimpleMongoClientDatabaseFactory(MongoProperties properties){
        MongoClientSettings.Builder builder = MongoClientSettings.builder();
        builder.applyConnectionString(new ConnectionString(properties.getUri()));
        builder.applyToConnectionPoolSettings(b -> {
            b.maxSize(maxSize);
            b.minSize(minSize);
            b.maxConnectionLifeTime(maxConnectionLifeTime, TimeUnit.SECONDS);
            b.maxConnectionIdleTime(maxConnectionIdleTime, TimeUnit.MINUTES);
            b.maxWaitTime(maxWaitTime, TimeUnit.MILLISECONDS);
        });
        MongoClient mongoClient = MongoClients.create(builder.build(), SpringDataMongoDB.driverInformation());
        return new SimpleMongoClientDatabaseFactory(mongoClient, properties.getDatabase());
    }

    /**
     * 模板工厂
     * @param mongoDatabaseFactory
     * @return
     */
    private MongoTemplate getMongoTemplate(MongoDatabaseFactory mongoDatabaseFactory){
        MongoTemplate mongoTemplate = new MongoTemplate(mongoDatabaseFactory);
        //去除保存实体时,spring data mongodb 自动添加的_class字段
        MappingMongoConverter mongoMapping = (MappingMongoConverter) mongoTemplate.getConverter();
        mongoMapping.setTypeMapper(new DefaultMongoTypeMapper(null));
        mongoMapping.afterPropertiesSet();
        return mongoTemplate;
    }
    //endregion



}
package org.example.controller;

import cn.hutool.core.util.StrUtil;
import com.mongodb.bulk.BulkWriteResult;
import com.mongodb.client.result.UpdateResult;
import org.bson.types.ObjectId;
import org.example.common.R;
import lombok.extern.slf4j.Slf4j;
import org.example.entity.TenderProject;
import org.example.utils.MongoUtil;
import org.example.utils.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.BulkOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.GroupOperation;
import org.springframework.data.mongodb.core.aggregation.MatchOperation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.util.Pair;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * @program: plus
 * @ClassName WelcomeController
 * @description:欢迎窗口
 * @author: AI
 * @create: 2023-10-31 15:10
 * @Version 1.0
 **/
@RestController
@RequestMapping("/api/welcome")
@Slf4j
public class WelcomeController {



    private MongoTemplate mongoTemplate;
    private MongoTemplate mongoTemplate2;
    /**
     * @Qualifier使用非默认数据库时必须加上
     * 方法或者属性注入时使用 @Qualifier(name = "xx")
     * 参数上使用 @Qualifier("xx")
     * @param mongoTemplate
     * @param mongoTemplate2
     */
    @Autowired
    public void setMongoTemplate(MongoTemplate mongoTemplate,
                                 @Qualifier("twoMongotemplate") MongoTemplate mongoTemplate2){
        this.mongoTemplate = mongoTemplate;
        this.mongoTemplate2 = mongoTemplate2;
    }


    @Resource
    private MongoUtil mongoUtil;

    /**
     * 普通查询
     * @return
     */
    @GetMapping("/hello")
    public R Hello() {

        Query query = new Query();

        //query.fields().include("id");//查询指定字段


        boolean flag = ObjectId.isValid("656e99610307387d9fc10797");//判断是否是16进制字符串,否则无法转化为objectId
        ObjectId objectId = new ObjectId("656e99610307387d9fc10797");
        query.addCriteria(Criteria.where("Tender.Ref._id").is(objectId));
        TenderProject projectList = mongoTemplate.findOne(query, TenderProject.class);


        Query query2 = new Query();
        boolean flag2 = ObjectId.isValid("656e99610307387d9fc10797");//判断是否是16进制字符串,否则无法转化为objectId
        ObjectId objectId2 = new ObjectId("5aceb7d88434881f541ba9a9");
        query2.addCriteria(Criteria.where("Tender.Ref._id").is(objectId2));
        TenderProject projectList2 = mongoTemplate2.findOne(query2, TenderProject.class);


        return R.data("您好,欢迎使用脚手架!");
    }

    /**
     * 统计查询
     * @return
     */
    @GetMapping("/query")
    public R query() {

        // 查询条件
        Criteria criteria = new Criteria();
        criteria.and("id").is("123");
        criteria.and("author").is("321");

        // 查询条件
        MatchOperation match = Aggregation.match(criteria);
        // 分组统计
        GroupOperation group = Aggregation.group()
                .count().as("totalBlog")
                .sum("countRead").as("totalRead")
                .avg("countRead").as("aveRead")
                .sum("countLike").as("totalLike")
                .avg("countLike").as("aveLike");
        // 查询结果
        AggregationResults<TenderProject> results = mongoTemplate.aggregate(Aggregation.newAggregation(TenderProject.class,
                match, group), TenderProject.class);

        return R.data("您好,欢迎使用脚手架!");
    }

    /**
     * 分页
     * @return
     */
    @GetMapping("/list")
    public R<PageHelper> list() {

        Query query = new Query();
        //query.addCriteria(Criteria.where("Tender.Ref._id").is(new ObjectId("656e99610307387d9fc10797")));
        query.with(Sort.by(Sort.Direction.DESC,"OpeningTime"));//排序降序
        mongoUtil.start(1, 10, query);
        List<TenderProject> list = mongoTemplate.find(query, TenderProject.class);
        long count = mongoTemplate.count(query, TenderProject.class);
        PageHelper pageHelper = mongoUtil.pageHelper(count, list);

        return R.data(pageHelper);
    }


    /**
     * 更新
     * @return
     */
    @GetMapping("/update")
    public R update() {

        Query query = new Query();
        query.addCriteria(Criteria.where("Tender.Ref._id").is(new ObjectId("656e99610307387d9fc10797")));
        Update update = new Update();


        //自主招标-园林绿化-20231205

//        //直接更新
//        update.set("Title", "自主招标-园林绿化-20231205");

//          //加入到一个集合中,不会重复
//          update.addToSet("students", "我是新加的键");

//          //移除这个键
//          update.unset("students");

//        //需要传值,会清空其他属性
//        update.addToSet("students");

//          //文档不存在的话会插入一条新的记录
//          update.setOnInsert("students", "我是新加的键");

        UpdateResult updateResult = mongoTemplate.updateFirst(query, update, TenderProject.class);
        if( updateResult.getModifiedCount() > 0){
            return R.data("修改成功");
        }else {
            return R.data("500",null,"更新失败");
        }

    }


    /**
     * 批量操作
     * @return
     */
    @GetMapping("/bulk")
    public R bulk() {


//        //批量插入示例
//        String collectionName = "";
//        List<TenderProject> insertDataList = new ArrayList<>();
//        BulkOperations operations = mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, collectionName);
//        operations.insert(insertDataList);
//        BulkWriteResult result = operations.execute();


        //批量修改
//        String collectionName = "";
//        List<TenderProject> updateDataList = new ArrayList<>();
//        BulkOperations operations = mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, collectionName);
//        updateDataList.forEach(data -> {
//            Query queryUpdate = new Query();
//            queryUpdate.addCriteria(Criteria.where("_id").is("id"));
//            Update update = new Update();
//            update.set("field1", "value1").set("field2", "value2");
//            operations.updateOne(queryUpdate, update);
//        });
//        BulkWriteResult result = operations.execute();


//        //利用BulkOperations的upsert方法可以同时支持插入和更新操作
//        //备注:BulkOperations.BulkMode.UNORDERED 和 BulkOperations.BulkMode.ORDERED的区别:
//        //UNORDERED是平行处理,即使某条记录出错了,其余的也会继续处理;
//        //ORDERED是队列排序处理,只要中途有个失败了,那么后续的操作流程就会终止了。
//        String collectionName = "";
//        List<TenderProject> dataList = new ArrayList<>();
//        List<Pair<Query, Update>> updateList = new ArrayList<>(dataList.size());
//        BulkOperations operations = mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, collectionName);
//        dataList.forEach(data -> {
//            Query query = new Query(new
//                    Criteria("field1").is("value1")).addCriteria(new Criteria("field2").is("value2"));
//            Update update = new Update();
//            for (int index = 0; index < dataList.size(); index++) {
//                TenderProject tp = dataList.get(index);
//                update.set(tp.get_IsDelete(), "value1").set(tp.getDOC_PRICE(), "value2");
//            }
//            Pair<Query, Update> updatePair = Pair.of(query, update);
//            updateList.add(updatePair);
//        });
//        operations.upsert(updateList);
//        BulkWriteResult result = operations.execute();


        return R.data("修改成功");
    }


}