Mongo 到 Postgres 迁移 - 将 mongo hexa Id 字段转换为更短的整数
Mongo to Postgres migration - Convert mongo hexa Id field to shorter integer
正在将 MongoDB 迁移到 postgres。
感谢 postgres JSON ,这使得移动嵌套文档变得容易 JSON。但问题始于迁移 "ID" 字段。
Mongo生成一个大的十六进制数56c4100560b2d8308f4bde21
我尝试将其转换为 BigInt,不幸的是它超出了范围 26397231623443762880753094891
无法重新生成ID,因为它在各处的文档之间相互链接。
字符串不能用作 ID 字段,因为我正在迁移到 Postgres + JPA,并且我将继续使用自动生成序列。
有什么办法,我可以将这个十六进制缩短为更短版本的 Int 或 BigInt ,同时我应该保持唯一性
我尝试取模,但它会带来重复
您最好的选择是将 MongoDB 的 ObjectId
字段迁移到 PostgreSQL 的 uuid
列。请注意,UUID 中有更多字节,因此您需要填充这些值。
查看更多信息:
如果你真的想使用bigint
s,你有两个选择:
1.创造全新的价值
- 创建您的架构(使用 tables、约束等)
- 在此架构中,使用
text
/ varchar
作为您的 ObjectId
值(目前)
- 为所有关系创建 foreign keys,为所有
ObjectId
列创建 ON UPDATE CASCADE
。
- 为具有
ObjectId
列的所有 table 创建 sequences。
更新 ObjectId
列(虽然它们仍然是 text
/ varchar
),其中:
UPDATE table_name
SET object_id_col = nextval('table_name_object_id_col_seq')::text
(这会将更改传播到引用 tables,因为外键已较早设置。)
- 删除外键
- 将这些
ObjectId
列的列类型更改为 bigint
- 将您的序列更改为
OWNED BY
table 列
- 更改 tables 以使用
nextval('table_name_object_id_col_seq')
作为默认值
- 重新添加外键
此方法保证在迁移过程中不会出现重复值。并且该序列可用于为主键创建新值。
2。以某种方式使用您的原始值
截断会导致信息丢失,因此无论您尝试什么方法,您可能最终得到重复值。但是,您可以使用 f.ex 来减少这种情况的发生。按位 XOR
(通常是 Postgre#
中的运算符SQL)而不是取模。
有了这个功能f.ex。您可以将原始值用作:
- 从
0
开始(或其他一些,固定起始值)
- 每次迭代,使用来自输入
的N个最低有效位
- 计算结果为
<the_previous_result> # <value_from_2.>
- 继续 2。当有更多未使用的位时(输入应该是旧输入,但 N 最低有效位)
这是一个 SQL 函数,它可以做到这一点:
create or replace function hex_xor(p_hex text, p_bits int default 64, p_default bigint default 0)
returns bigint
language sql
immutable
as $func$
with recursive r as (
select ('x' || p_hex)::varbit h, p_default r, 0 i
union all
select case
when bit_length(h) <= p_bits then varbit ''
else substring(h for bit_length(h) - p_bits)
end,
r # case
when bit_length(h) <= p_bits then h::bit(64)::bigint
else substring(h from bit_length(h) - p_bits + 1 for p_bits)::bigint
end,
i + 1
from r
where bit_length(h) > 0
)
select r
from r
order by i desc
limit 1
$func$;
这假设 p_hex
参数确实是十六进制格式并且 p_bits
参数永远不会大于 64
。
但是如果你只是按原样使用它,你可能会在稍后结束,在 INSERT
上出现冲突的值。你能做的是f.ex。使用:
select -hex_xor('56c4100560b2d8308f4bde21', 63)
迁移后。这样,迁移的 ObjectId
s 将始终为负值,之后生成的主键(f.ex。来自序列)将始终为正值。
正在将 MongoDB 迁移到 postgres。
感谢 postgres JSON ,这使得移动嵌套文档变得容易 JSON。但问题始于迁移 "ID" 字段。
Mongo生成一个大的十六进制数56c4100560b2d8308f4bde21
我尝试将其转换为 BigInt,不幸的是它超出了范围 26397231623443762880753094891
无法重新生成ID,因为它在各处的文档之间相互链接。
字符串不能用作 ID 字段,因为我正在迁移到 Postgres + JPA,并且我将继续使用自动生成序列。
有什么办法,我可以将这个十六进制缩短为更短版本的 Int 或 BigInt ,同时我应该保持唯一性
我尝试取模,但它会带来重复
您最好的选择是将 MongoDB 的 ObjectId
字段迁移到 PostgreSQL 的 uuid
列。请注意,UUID 中有更多字节,因此您需要填充这些值。
查看更多信息:
如果你真的想使用bigint
s,你有两个选择:
1.创造全新的价值
- 创建您的架构(使用 tables、约束等)
- 在此架构中,使用
text
/varchar
作为您的ObjectId
值(目前)
- 在此架构中,使用
- 为所有关系创建 foreign keys,为所有
ObjectId
列创建ON UPDATE CASCADE
。 - 为具有
ObjectId
列的所有 table 创建 sequences。 更新
ObjectId
列(虽然它们仍然是text
/varchar
),其中:UPDATE table_name SET object_id_col = nextval('table_name_object_id_col_seq')::text
(这会将更改传播到引用 tables,因为外键已较早设置。)
- 删除外键
- 将这些
ObjectId
列的列类型更改为bigint
- 将您的序列更改为
OWNED BY
table 列 - 更改 tables 以使用
nextval('table_name_object_id_col_seq')
作为默认值 - 重新添加外键
此方法保证在迁移过程中不会出现重复值。并且该序列可用于为主键创建新值。
2。以某种方式使用您的原始值
截断会导致信息丢失,因此无论您尝试什么方法,您可能最终得到重复值。但是,您可以使用 f.ex 来减少这种情况的发生。按位 XOR
(通常是 Postgre#
中的运算符SQL)而不是取模。
有了这个功能f.ex。您可以将原始值用作:
- 从
0
开始(或其他一些,固定起始值) - 每次迭代,使用来自输入 的N个最低有效位
- 计算结果为
<the_previous_result> # <value_from_2.>
- 继续 2。当有更多未使用的位时(输入应该是旧输入,但 N 最低有效位)
这是一个 SQL 函数,它可以做到这一点:
create or replace function hex_xor(p_hex text, p_bits int default 64, p_default bigint default 0)
returns bigint
language sql
immutable
as $func$
with recursive r as (
select ('x' || p_hex)::varbit h, p_default r, 0 i
union all
select case
when bit_length(h) <= p_bits then varbit ''
else substring(h for bit_length(h) - p_bits)
end,
r # case
when bit_length(h) <= p_bits then h::bit(64)::bigint
else substring(h from bit_length(h) - p_bits + 1 for p_bits)::bigint
end,
i + 1
from r
where bit_length(h) > 0
)
select r
from r
order by i desc
limit 1
$func$;
这假设 p_hex
参数确实是十六进制格式并且 p_bits
参数永远不会大于 64
。
但是如果你只是按原样使用它,你可能会在稍后结束,在 INSERT
上出现冲突的值。你能做的是f.ex。使用:
select -hex_xor('56c4100560b2d8308f4bde21', 63)
迁移后。这样,迁移的 ObjectId
s 将始终为负值,之后生成的主键(f.ex。来自序列)将始终为正值。