跳到主要内容

AI 问题汇总

· 阅读需 1 分钟

记录询问 AI 的问题与答案

Docker

1. docker compose pull && docker compose down && docker compose up -d 命令优化

重新创建并重启服务

# 最简洁的方式 - 重新创建并启动服务
docker compose up -d --pull always --force-recreate

拉取镜像并重启有变化的服务

docker compose up -d --pull always

场景安全的滚动更新

docker compose pull && docker compose up -d --no-deps --force-recreate

Git 常用命令

· 阅读需 1 分钟

git log

--since 语法

  1. 绝对日期格式
    • YYYY-MM-DD
    • Month Day, Year
    • YYYY-MM-DD HH:mm:ss
  2. 相对时间格式
    • N year/months/weeks/days/hours/minutes/seconds ago
    • yesterday/today
  3. --until --before 结合
    • --since>=
    • --until, 即 <

从今天开始,过去 1 个月的提交

git log --since="1 month ago"

一行显示

git log --since="2025-06-01" --until="2025-07-01" --oneline

自定义输出

# %h commit hash 的缩写
# %an 作者
# %ar 提交的相对时间
# %s 提交信息
git log --since="1 month ago" --pretty=format:"%h - %an, %ar : %s"

图形化显示

git log --since="1 month ago" --graph --oneline

问题记录

· 阅读需 1 分钟

2025.6.27

  1. 序列化与反序列
    • 兼容多种日志格式
    • jackson、gson、fastjson 的写法
  2. Dockerfile 构建优化技巧

Docker Image

· 阅读需 1 分钟

watchtower

自动检测并更新 docker image

version: "3"
services:
watchtower:
image: containrrr/watchtower
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: --interval 3600 # 每小时检查一次更新

自解释代码

· 阅读需 2 分钟

summary

  1. 使用命名常量而非晦涩的错误代码 | Using named constants instead of cryptic error codes
  2. 将复杂逻辑抽离成独立函数 | Extracting complex logic and putting it in its own function
  3. 运用短路求值使代码流程线性化 | Using short-circuit evaluation to make the code flow linear
  4. 引入类型注解辅助静态检查与实时编码反馈 | Introducing type annotations to help with static type checking and real-time coding feedback

original code

async function createUser(user) {
if (!validateUserInput(user)) {
throw new Error('u105');
}

const rules = [/[a-z]{1,}/, /[A-Z]{1,}/, /[0-9]{1,}/, /\W{1,}/];
if (user.password.length >= 8 && rules.every((rule) => rule.test(user.password))) {
if (await userService.getUserByEmail(user.email)) {
throw new Error('u212');
}
} else {
throw new Error('u201');
}

user.password = await hashPassword(user.password);
return userService.create(user);
}

命名常量与单一职责原则

const err = {
userValidationFailed: 'u105',
userExists: 'u212',
invalidPassword: 'u201',
};

function isPasswordValid(password) {
const rules = [/[a-z]{1,}/, /[A-Z]{1,}/, /[0-9]{1,}/, /\W{1,}/];
return password.length >= 8 && rules.every((rule) => rule.test(password));
}

async function createUser(user) {
if (!validateUserInput(user)) {
throw new Error(err.userValidationFailed);
}

if (isPasswordValid(user.password)) {
if (await userService.getUserByEmail(user.email)) {
throw new Error(err.userExists);
}
} else {
throw new Error(err.invalidPassword);
}

user.password = await hashPassword(user.password);
return userService.create(user);
}

短路求值

function throwError(error) {
throw new Error(error);
}

async function createUser(user) {
validateUserInput(user) || throwError(err.userValidationFailed);
isPasswordValid(user.password) || throwError(err.invalidPassword);
!(await userService.getUserByEmail(user.email)) || throwError(err.userExists);

user.password = await hashPassword(user.password);
return userService.create(user);
}

Keeping a Mistake Journal

· 阅读需 1 分钟

Entry Format

Name:名称,简明扼要的标题。
Tags:标签,分类
Context:背景,错误发生的具体环境或情境。
Problem:问题,对错误本身的描述。
Impacts:影响,可能导致的后果。
Lessons learned:经验总结,从这次错误中学到了什么。
Correction plan: 改进方案,今后如何避免重蹈覆辙。
Latest occurrence:最近发送,上次犯这个错误的时间。
Repetition: 重复次数,这个错误发送的概率。

awk 命令基本使用

· 阅读需 4 分钟

awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。

默认分隔符是:空白键或者 tab 建,以 \n 为一行

$0:所有域
$n:第 n 个域

1、显示出最近登录成功的用户

使用默认分隔符

last -n 5 | awk '{print $1}'

2、查看用户

通过 -F ':' 指定分隔符

# 下面两个命令等效
cat /etc/passwd | awk -F ':' '{print $1}'
cat /etc/passwd | awk -F: '{print $1}'

3、查看用户的时候显示出 bash

通过双引号对 \t 转义

cat /etc/passwd | awk -F ':' '{print $1"\t"$7}'

4、BEGIN、END 使用

cat /etc/passwd | awk -F ':' 'BEGIN {"name,bash"} {print $1","$7} END {print "blue,/bin/nosh"}'

5、匹配含有关键字的行

'/pattern/action' 指定正则表达式和 action

awk -F ':' '/root/' /etc/passwd
awk -F ':' '/root/{print $7}' /etc/passwd

6、awk 内置变量

ARGC               命令行参数个数
ARGV 命令行参数排列
ENVIRON 支持队列中系统环境变量的使用
FILENAME awk浏览的文件名
FNR 浏览文件的记录数
FS 设置输入域分隔符,等价于命令行 -F选项
NF 浏览记录的域的个数
NR 已读的记录数
OFS 输出域分隔符
ORS 输出记录分隔符
RS 控制记录分隔符
awk -F ':' '{print $1 "\tfilename:" FILENAME "\t\tARGC:" ARGC "\tFNR:" FNR}' aa.txt 

7、print、printf

print函数的参数可以是变量、数值或者字符串。字符串必须用双引号引用,参数用逗号分隔。如果没有逗号,参数就串联在一起而无法区分。这里,逗号的作用与输出文件的分隔符的作用是一样的,只是后者是空格而已。

printf函数,其用法和c语言中printf基本相似,可以格式化字符串,输出复杂时,printf更加好用,代码更易懂。

8、自定义变量

awk -F ':' 'BEGIN {count=0; print "[start] user count is "count}{ count++; print $1"\t" count} END {print "user count is " count}' /etc/passwd

统计某个文件夹下的文件占用的字节数

ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size}'

如果以M为单位显示:

ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size/1024/1024,"M"}'

9、显示账户

awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i < NR; i++) print i, name[i]}' /etc/passwd

查看拒绝访问的 IP

awk -F ':' '{print $2}' /etc/hosts.deny| sort | uniq -c | awk '{print $1"\t"$2}' | grep  '^[0-9]' 

MongoDB 常用查询语句/技巧

· 阅读需 2 分钟

转换为 UTC 时间字符串

// 转换为 UTC 时间字符串
db.collection.find({
timestamp: { $gte: new Date( new Date("2025-03-22T00:00:00+08:00").toISOString()) }
});

创建视图

标准视图使用底层集合的索引。

// ==============  AI800 A相进线温度  ==========
db.AI800.drop();
db.createView(
"AI800", // 视图名称
"equipment-1123", // 源集合
[
{ $match: { "code": "AI424" } }, // 过滤条件
]
)

db.AI800.find();

MongoDB 储存空间优化

数据库状态查询

db.status()

db.stats(1024*1024); // 输出单位为 MB

查询结果说明:

{
"db": "tmp_dev",
"collections": Long("275"),
"views": Long("0"),
"objects": Long("7891781"), // 文档总数
"avgObjSize": 234.529085766572, // 单个文档的平均大小,单位是:byte
"dataSize": 1765.11019039154, // 逻辑大小,不压缩的情况下,数据大小
"storageSize": 299.5, // 物理大小
"indexes": Long("281"), // 索引数量
"indexSize": 123.61328125, // 索引占用的存储空间
"totalSize": 423.11328125, // 总存储空间 = storageSize + indexSize
"scaleFactor": Long("1048576"), // 缩放因子, 1048576 = 1024 * 1024, 即 MB
"fsUsedSize": 126627.28515625, // 文件系统已使用的存储空间
"fsTotalSize": 181303.5546875, // 文件系统总存储空间
"ok": 1
}

空间优化

1. 删除 collection 是可以直接释放空间的

2. 删除 collection 里面的数据是不会直接释放空间,需要执行 db.runCommand({compact:"collectuinName"})

优化脚本

for (var collectionName of db.getCollectionNames()) {
// 清空数据
if (collectionName.startsWith("equipment")
|| collectionName.startsWith("transformer")
|| collectionName.startsWith("circuit-breaker")) {
// db.getCollection(collectionName).deleteMany({});
// db.runCommand({
// compact: collectionName
// })
db.getCollection(collectionName).drop();
}
}

字段排序

.sort(), 1 增序, -1 降序。

db.getCollection("transformer-1000").find({
"code": "AI801"
}).sort({
"dataTime": -1
}).limit(1000);