中间件--MongoDB部署及初始化js脚本(docker部署,docker-entrypoint-initdb.d,数据迁移,自动化部署)

一、概述

MongoDB是一种常见的Nosql数据库(非关系型数据库),以文档(Document)的形式存储数据。是非关系型数据库中最像关系型数据库的一种。本篇主要介绍下部署和数据迁移。

在 MongoDB 官方镜像部署介绍中,MongoDB 的官方镜像会在容器首次启动时自动执行 docker-entrypoint-initdb.d/ 目录下的所有.js 文件(注意:只会在容器创建的第一次会执行,如果是运行之前已有的容器则不会执行),我们可以利用这一点来实现数据的迁移和自动化部署服务。

二、完整部署和迁移过程:

1、删除之前的容器

因为js脚本仅会在初次创建容器启动时才会被执行。如果是已存在的容器重新运行,js脚本是不会被执行的。所以如果之前有运行的容器,需要删除。
命令:

bash 复制代码
docker rm -f mongdb-with-js

删除示例:

2、编写Dockerfile脚本

因为我们要把我们指定的js文件压到官方的mongDB镜像中,所以这里需要编写Dockerfile文件,用来重新构建镜像。

Dockerfile示例:

c 复制代码
# 使用自定义的 MongoDB 镜像
FROM mongo:7.0.4

# 维护者信息
MAINTAINER weisian

# 设置时区为上海
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

# 将 object-mongo.js 文件复制到容器的初始化脚本目录
COPY ./object-mongo.js /docker-entrypoint-initdb.d

3、编写用于初始化的js脚本

该js文件会被Dockerfile文件压入到镜像中。本例的js脚本就是需要初始化到库中的数据。

名称如

object-mongo.js

代码示例:

javascript 复制代码
console.log("start running js!!!");
const db = db.getSiblingDB("object_cloud");     // 指定库的名称

try {
  console.log("Switching to database: object_cloud");
  console.log("Inserting data into object_sensor_category...");
  
  // 在object_cloud库的object_sensor_category表中插入数据(支持many和one两种方法)
  const result = db.object_sensor_category.insertMany([
	{
		"_id" : NumberLong("988405030841225243"),
		"sensorModel" : "DT-ZD-V1001",
		"vibrateIndicators" : [ 
			"rms", 
			"peak"
		],
		"params" : {
			"frequencyResponse" : 22,
			"sensitivity" : 102
		},
		"deleteFlag" : false,
		"createTime" : ISODate("2024-06-20T03:28:43.030Z")
	},
	{
		"_id" : NumberLong("988405030841225244"),
		"sensorModel" : "DT-ZS-V1001",
		"pointTypeList" : [ 
			{
				"pointType" : 1020,
				"dataBizTypes" : [ 
					1020
				]
			}
		],
		"params" : {
			"workmanshipCollectInterval" : 60,
			"triggerCount" : 30
		},
		"createTime" : ISODate("2024-06-20T03:28:43.030Z"),
		"createUser" : "1543837863788879871"
	}
  ]);

  const result2 = db.object_category.insertMany([
    {
		"_id" : NumberLong("988108368994373658"),
		"collectorChannelNum" : 18,
		"channelConfList" : [ 
			{
				"channelType" : "1020",
				"sensorTypeList" : [ 
					NumberLong("988405030841225244")
				]
			}
		],
		"manufacturerId" : NumberLong("7382949823"),
		"workmanshipExist" : [ 
			NumberLong(1060)
		],
		"sensorTypeList" : [ 
			NumberLong("988404952147693592"), 
			NumberLong("988405030841225242")
		],
		"updateTime" : ISODate("2024-06-19T07:49:53.351Z"),
		"updateUser" : "1543837863788879871"
	}
  ]);

} catch (e) {
  console.error("Error inserting data: " + e);
}

4、重新构建镜像

(1)、创建工作路径

随意创建一个目录即可。

上传前面编写的Dockerfile和object-mongo.js两个文件

(2)、重新构建镜像image-mongodb-js:1.0
命令:

bash 复制代码
docker build -t image-mongodb-js:1.0 .

(3)、查询镜像存在

5、启动mongodb服务

(1)、指定用户名(root),密码(123456),和镜像
命令:

bash 复制代码
docker run -d --name mongodb-with-js -p 27017:27017 -e MONGO_INITDB_ROOT_USERNAME=root -e MONGO_INITDB_ROOT_PASSWORD=123456 image-mongodb-js:1.0

(2)、查看启动日志
命令:

bash 复制代码
docker logs mongodb-with-js

可以看到object-mongo.js中打印的日志信息,方便查看是否初始化js等操作信息。

6、客户端连接验证

使用如下的IP、端口,用户名,密码连接mongDb服务。

ip:27017

root/123456

可以看到登录成功,且数据初始化完成。

7、过程中的几个命令记一下

bash 复制代码
进入容器
docker exec -it 415dc88956bd bash
停止并删除容器
docker rm -f mongodb-with-js
删除镜像
docker rmi image-mongodb-js:1.0
宿主机打开mongo shell窗口(可执行原始的mongo命令,在mongDB5.0及之后改为mongosh)(如果进入容器内直接*mongosh即可打开)
docker exec -it mongodb-with-js mongosh

以下几个为mong shell的脚本:

展示mongo服务中有哪些个数据库
show databases
切换数据库
use phm_local
展示当前数据库下的表
show collections
展示当前数据库下,指定表中的数据
db.object_sensor_category.find().pretty();
加载执行js脚本
load("/docker-entrypoint-initdb.d/phm-mongo.js")

三、js脚本需要注意的点

(1)、Long类型的精度问题

在处理long类型时,如果不用双引号框起来会造成精度丢失问题甚至报错。如下为正确和错误的示例。

正确示例:

javascript 复制代码
"_id" : NumberLong("988404952147693592"),

错误示例如:
"_id" : NumberLong(988404952147693592),

(2)、注意mongDb的版本

使用5.0之前和之后的mongDb版本,js语法可能会不相同。

目前使用7.0.4版本,可用语法如下:

javascript 复制代码
const db = db.getSiblingDB("object_cloud");   // 切换到object_cloud库
const result = db.object_sensor_category.insertMany([])   // db库导入多条数据

(3)、时间对象

时间对象需要改成以下格式,注意后面也有双引号

javascript 复制代码
"createTime" : ISODate("2024-06-20T03:28:24.269Z")

四、通过代码做数据迁移

通过如下的代码,也可以实现mongoDb数据的迁移工作。但这种方式要求必须同时连接到两个数据源,对于一些线上环境往往是平常无法访问的。如果网络环境不通的情况下,就只能先把数据导出后,在迁移到目标环境中进行导入的工作(上面的js初始化方式也是这种实现的逻辑,但是不同在于js的方式实现了自动化部署,即:不需要人为再去操作迁移了)

java代码示例如下:

java 复制代码
import com.alibaba.fastjson2.JSON;
import com.mongodb.MongoClientSettings;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.*;
import org.bson.Document;
import java.util.Collections;
import java.util.Iterator;

public class MongoMigration {

    public static void main(String[] args) {
        String[] collections = new String[]{    // 指定需要迁移数据的表
                "object_category",
//                "object_running_conf",
                "object_sensor_category"
        };
        for (String collection:collections){
            copyCollection(collection);       // 遍历上面的表进行数据迁移
        }
    }

    private static void copyCollection(String collection) {
        // 源MongoDB配置
        String sourceHost = "";
        int sourcePort = 27017;
        String sourceDatabase = "object-cloud";
        String sourceUsername = "root"; // 如果需要的话
        String sourcePassword = "123456"; // 如果需要的话

        // 目标MongoDB配置
        String targetHost = "";
        int targetPort = 38630; 
        String targetDatabase = "object-cloud";
        String targetUsername = "root"; // 如果需要的话
        String targetPassword = "123456"; // 如果需要的话

        // 连接到源MongoDB
        MongoClient sourceClient = createMongoClient(sourceHost, sourcePort, sourceDatabase, sourceUsername, sourcePassword);
        MongoDatabase sourceDatabaseInstance = sourceClient.getDatabase(sourceDatabase);
        MongoCollection<Document> sourceCollectionInstance = sourceDatabaseInstance.getCollection(collection);

        // 连接到目标MongoDB
        MongoClient targetClient = createMongoClient(targetHost, targetPort,  targetDatabase ,targetUsername, targetPassword);
        MongoDatabase targetDatabaseInstance = targetClient.getDatabase(targetDatabase);
        MongoCollection<Document> targetCollectionInstance = targetDatabaseInstance.getCollection(collection);

        // 从源集合读取数据并写入目标集合
        FindIterable<Document> documents = sourceCollectionInstance.find();
        Iterator<Document> iterator = sourceCollectionInstance.find().iterator();
        int i=0;
        while (iterator.hasNext()) {
            Document doc = iterator.next();
            targetCollectionInstance.insertOne(doc);
            if (++i>100){                  // 仅迁移前100条数据,有些表数据量太大,不需要可以放弃。如果需要全量,这里要删除掉
                break;
            }
        }

        // 关闭连接
        sourceClient.close();
        targetClient.close();
        System.out.println("Data migration completed successfully!");
    }

    private static MongoClient createMongoClient(String host, int port, String  database, String username, String password) {
        MongoCredential credential = null;
        if (username != null && !username.isEmpty() && password != null && !password.isEmpty()) {
            credential = MongoCredential.createCredential(username, database, password.toCharArray()); 
        }
        MongoClientSettings settings = MongoClientSettings.builder()
                .applyToClusterSettings(builder ->
                        builder.hosts(Collections.singletonList(new ServerAddress(host, port))))
                .credential(credential) // 如果需要认证
                .build();
        return MongoClients.create(settings);
    }
}

五、总结

通过MongDB官方镜像的特性,会在容器首次启动时自动执行 docker-entrypoint-initdb.d/ 目录下的所有.js 文件,可以利用这一点来实现mongDB的数据迁移或自动化部署服务。

学海无涯苦作舟!!!

相关推荐
liuweni几秒前
Next.js系统性教学:深入理解缓存交互与API缓存管理
开发语言·前端·javascript·经验分享·缓存·前端框架·交互
Domain-zhuo42 分钟前
React的功能是什么?
前端·javascript·react native·react.js·前端框架·ecmascript
Jiaberrr1 小时前
微信小程序中 crypto-js 加解密全攻略
前端·javascript·vue.js·微信小程序·小程序
此星光明1 小时前
GEE训练教程——ECMWF/ERA5_LAND/DAILY_AGGR数据的地表温度的时序分析
javascript·gee·图表·温度·时序·摄氏度
聚名网2 小时前
什么叫中间件服务器?
运维·服务器·中间件
m0_748235244 小时前
前端:HTML、CSS、JS、Vue
前端·javascript·html
Charonmomo4 小时前
React - echarts 世界地图,中国地图绘制
javascript·react.js·echarts
灵性(๑>ڡ<)☆4 小时前
智慧商城项目2(vue核心技术与实战)
前端·javascript·vue.js
没资格抱怨5 小时前
分配角色业务
javascript·vue.js·elementui