PostgreSQL/Sequelize是否有MongoDB $addToSet的等效数组去重添加功能?
当然有啦!在PostgreSQL和Sequelize里,都能实现类似MongoDB $addToSet的「仅添加不存在元素到数组」的功能,我来给你拆解说明:
PostgreSQL对数组类型有很灵活的支持,有两种常用方式实现需求:
方式一:用WHERE条件过滤,仅更新元素不存在的行
这种方式更高效,直接在WHERE子句里判断元素是否不在数组中,只有符合条件的行才会执行更新操作。比如你要给users表中id=1的用户,往favorite_numbers(整数数组)里添加数字5:UPDATE users SET favorite_numbers = array_append(favorite_numbers, 5) WHERE id = 1 AND array_position(favorite_numbers, 5) IS NULL;array_position函数会返回元素在数组中的位置,如果返回NULL就说明元素不存在。方式二:用CASE语句做条件更新
如果你需要确保无论元素是否存在,都执行更新(只是存在时不改变数组),可以用CASE语句:UPDATE users SET favorite_numbers = CASE WHEN NOT (5 = ANY(favorite_numbers)) THEN favorite_numbers || 5 ELSE favorite_numbers END WHERE id = 1;5 = ANY(favorite_numbers)会检查5是否在数组中,不在的话就用||运算符追加元素。
在Sequelize里,你可以结合原生SQL片段(用literal)或者Sequelize的运算符来实现:
方式一:结合WHERE条件和
array_append
先导入Sequelize的运算符,然后在更新时过滤出元素不存在的行:const { Op } = require('sequelize'); const User = require('./models/User'); async function addNumberToUser(userId, numberToAdd) { await User.update( { favoriteNumbers: sequelize.literal(`array_append("favoriteNumbers", ${numberToAdd})`) }, { where: { id: userId, [Op.not]: { favoriteNumbers: { [Op.any]: [numberToAdd] } } } } ); }方式二:用CASE语句的SQL片段
如果你需要保证更新语句总会执行(即使元素已存在),可以用literal写CASE逻辑:async function addNumberToUser(userId, numberToAdd) { await User.update( { favoriteNumbers: sequelize.literal(` CASE WHEN NOT (${numberToAdd} = ANY("favoriteNumbers")) THEN "favoriteNumbers" || ${numberToAdd} ELSE "favoriteNumbers" END `) }, { where: { id: userId } } ); }
👉 注意:如果你的数组是JSONB类型而非PostgreSQL原生数组,逻辑类似但要改用JSONB相关的函数(比如jsonb_contains),不过优先推荐使用原生数组类型,性能更优。
内容的提问来源于stack exchange,提问作者Meni Edri

