【问题标题】:Mongo to Postgres migration - Convert mongo hexa Id field to shorter integerMongo 到 Postgres 迁移 - 将 mongo hexa Id 字段转换为更短的整数
【发布时间】:2017-03-27 06:51:54
【问题描述】:

正在将 MongoDB 迁移到 postgres。

感谢 postgres JSON,这使得将嵌套文档作为 JSON 移动变得容易。但问题始于迁移“ID”字段。

Mongo 生成一个大的十六进制数56c4100560b2d8308f4bde21

我尝试将其转换为 BigInt,但不幸的是它超出了范围 26397231623443762880753094891

  1. ID 无法重新生成,因为它在各处的文档之间相互关联。

  2. 字符串不能用作 ID 字段,因为我正在迁移到 Postgres + JPA,并且我将使用自动生成序列向前移动。

有什么办法,我可以将这个十六进制缩短为 Int 或 BigInt 的更短版本,同时我应该保持唯一性

我尝试取模,但它带来了重复

【问题讨论】:

  • 我想你可以使用与 bytea 相同的十六进制
  • ID 应该是 int/bigint。不幸的是我无法改变它
  • 那么你可能需要一些映射。就像创建一个 bigint 序列用作 ID 和迁移数据保存映射 old_hex -> new_int 某处
  • 通常,这些字段被迁移为uuid field(这通常在 JPA 实现中得到很好的支持:例如,您可以不止一种方式生成随机 UUID)——当您想使用原始值作为bigint f.ex。 (并希望使用自动递增的值)存在一个问题:如果现有行中出现一个小值,您的解决方案将在达到它时开始拒绝一些 INSERT

标签: mongodb postgresql int migration bigint


【解决方案1】:

您最好的选择是将 MongoDB 的 ObjectId 字段迁移到 PostgreSQL 的 uuid 列。请注意,UUID 中有更多字节,因此您需要填充这些值。

查看更多信息:

如果你真的想使用bigints,你有两种选择:

1.创造全新的价值

  1. 创建您的架构(使用表、约束等)
    • 在此架构中,使用 text / varchar 作为您的 ObjectId 值(暂时)
  2. 为所有关系创建foreign keys,为所有ObjectId 列创建ON UPDATE CASCADE
  3. 为所有具有ObjectId 列的表创建sequences
  4. 更新ObjectId 列(虽然它们仍然是text / varchar),使用:

    UPDATE table_name
    SET    object_id_col = nextval('table_name_object_id_col_seq')::text
    

    (这会将更改传播到引用表,因为之前设置了外键。)

  5. 删除外键
  6. 将这些ObjectId 列的列类型更改为bigint
  7. 将您的序列更改为 OWNED BY 表格列
  8. 更改表以使用 nextval('table_name_object_id_col_seq') 作为默认值
  9. 重新添加外键

此方法保证在迁移期间绝不会导致重复值。并且该序列可用于为主键创建新值。

2。以某种方式使用您的原始值

截断会导致信息丢失,所以你可能最终得到重复的值,无论你尝试什么方法。但是,您可以通过使用 f.ex 来减少这种情况的发生。按位 XOR(通常是 PostgreSQL 中的 # 运算符)而不是模数。

有了这个功能 f.ex.您可以将原始值用作:

  1. 0 开头(或其他一些,修正起始值)
  2. 在每次迭代中,使用 N 个来自输入的最低有效位
  3. 计算结果为<the_previous_result> # <value_from_2.>
  4. 继续 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)

迁移时。这种方式迁移的ObjectIds 将始终为负值,而稍后生成的主键(例如,来自序列)将始终为正值。

http://rextester.com/RCVFN77368

【讨论】:

    猜你喜欢
    • 2016-07-01
    • 2021-12-23
    • 2017-08-25
    • 2021-08-28
    • 2020-01-27
    • 1970-01-01
    • 2016-12-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多