Traverse Tree in Nodejs with Promises - node.js

Given a simple user tree:
users:
id | name | parent_id
1 | Bob | NULL
2 | Jan | 1
3 | Mat | 2
4 | Irene | 2
5 | Ellie | 2
6 | Laura | 5
7 | Uma | 6
I am trying to walk it with this code:
addChildren: function(db, treeUsers, parentId) {
const main = this;
var sql = Sql.select().from('users')
.where('parent_id = ?', parentId)
.toParam();
return db.execute(sql.text, sql.values)
.then(function([rs,meta]) {
rs.map(function(obj) {
treeUsers[obj.id] = obj;
});
return treeUsers;
});
},
getTreeUsers: function(db, depth) {
const main = this;
const rootNodeId = 1;
var treeUsers = {};
const getChildren = function(parentId) {
return main.addChildren(db, treeUsers, parentId).then(function(children) {
treeUsers = Object.assign(treeUsers, children);
--depth;
if(depth < 1) {
return Promise.resolve(treeUsers);
}
return Promise.all(Object.keys(children).map(function(id) {
return getChildren(id);
}));
};
return getChildren(rootNodeId);
});
The desired output would like this:
{
'2': { id: 2, name: 'Jan' , parent_id: 2 },
'3': { id: 3, name: 'Mat' , parent_id: 2 },
'4': { id: 4, name: 'Irene', parent_id: 2 },
'5': { id: 5, name: 'Ellie', parent_id: 2 },
'6': { id: 6, name: 'Laura', parent_id: 5 },
'7': { id: 7, name: 'Uma' , parent_id: 6 }
}
Right now I'm getting an more like this:
[[ {
'2': { id: 2, name: 'Jan' , parent_id: 2 },
'3': { id: 3, name: 'Mat' , parent_id: 2 },
'4': { id: 4, name: 'Irene', parent_id: 2 },
'5': { id: 5, name: 'Ellie', parent_id: 2 },
'6': { id: 6, name: 'Laura', parent_id: 5 },
'7': { id: 7, name: 'Uma' , parent_id: 6 }
} ],
[ {
'2': { id: 2, name: 'Jan' , parent_id: 2 },
'3': { id: 3, name: 'Mat' , parent_id: 2 },
'4': { id: 4, name: 'Irene', parent_id: 2 },
'5': { id: 5, name: 'Ellie', parent_id: 2 },
'6': { id: 6, name: 'Laura', parent_id: 5 },
'7': { id: 7, name: 'Uma' , parent_id: 6 }
} ],
[ {
'2': { id: 2, name: 'Jan' , parent_id: 2 },
'3': { id: 3, name: 'Mat' , parent_id: 2 },
'4': { id: 4, name: 'Irene', parent_id: 2 },
'5': { id: 5, name: 'Ellie', parent_id: 2 },
'6': { id: 6, name: 'Laura', parent_id: 5 },
'7': { id: 7, name: 'Uma' , parent_id: 6 }
} ] ... ]
I'm positive that the problem is the Promise.all(getChildren(..)) call, but I'm not sure how to refactor so that I get back exactly the one final result set.

Some issues:
You mutate the treeUsers object in both methods, which means that the object you resolve with, will still be mutated later. Note how you only have one instance of that object for one call of getTreeUsers. Note that the assignment in:
treeUsers = Object.assign(treeUsers, children);
does not do anything, as Object.assign already mutates the first argument anyway.
Promise.all resolves to an array value, where each element contains the treeUsers object. As it was mutated by all separate calls, all these array entries point to the same object reference, explaining the repetitions you see
depth is a variable common to each call to getChildren. It would be safer to pass it as argument to be sure that siblings are expanded with the same value for depth
I would just avoid passing the treeUsers object around, as it should really be just the resolved value. Let each promise resolve to the children it can "see" and consolidate the results after each Promise.all promise resolves.
Here is how that could look:
addChildren: function(db, treeUsers, parentId) {
const main = this,
sql = Sql.select().from('users')
.where('parent_id = ?', parentId)
.toParam();
return db.execute(sql.text, sql.values).then(function([rs,meta]) {
// Create a new(!) object and return it
return Object.assign(...rs.map(function(obj) {
return { [obj.id]: obj };
}));
});
},
getTreeUsers: function(db, depth) {
const main = this,
rootNodeId = 1;
const getChildren = function(parentId, depth) { // pass depth
return main.addChildren(db, parentId).then(function(children) {
if (depth <= 1) {
return children; // only the children. No need for Promise.resolve
}
return Promise.all(Object.keys(children).map(function(id) {
return getChildren(id, depth - 1); // pass depth
})).then(arr => Object.assign(children, ...arr)); // consolidate
});
}
return getChildren(rootNodeId, depth);
}

Yes, Promise.all always returns an array of all the result values. When your calls all return promises that fulfill with the same value, treeUsers, you get an array of those objects. As you always want to make getChildren return always just that object, you can simplify to
function getChildren(parentId) {
return main.addChildren(db, treeUsers, parentId).then(function(children) {
Object.assign(treeUsers, children);
// when `children` is empty, the recursion terminates here
return Promise.all(Object.keys(children).map(getChildren)).then(() =>
treeUsers
);
});
}
(Of course this does not produce a tree structure)

Related

How can I sort objects by the value of one of the keys

So I've been trying to sort the following object and ive been having some trouble:
let obj = {
"1": {
"name": "card1",
"ryo": 3
},
"2": {
"name": "card2",
"ryo": 7
},
"3": {
"name": "card3",
"ryo": 2
}
}
Object.fromEntries(Object.entries(obj).sort((x, y) => y[1].ryo - x[1].ryo));
The code above returns:
{
'1': { name: 'card1', ryo: 3 },
'2': { name: 'card2', ryo: 7 },
'3': { name: 'card3', ryo: 2 }
}
my goal is to get it to return:
{
'2': { name: 'card2', ryo: 7 },
'1': { name: 'card1', ryo: 3 },
'3': { name: 'card3', ryo: 2 }
}
As simple as it seems I just cant get it to work and I dont know why it wont sort.
Edit: Id like to add that im trying to sort the object by ryo in descending order.
You can try converting to an array then sorting like this
let sorted = Object.entries(obj).sort(function(a, b) {
return b[1].ryo - a[1].ryo
});

Find sum of objects inside array using reduce

I am trying to find the total from objects inside an array, which each object has a price and quantity,
i can find the total when the array has exactly two objects, but for more than two it produces NaN.
arr = [ { quantity: 1, price: 30 },
{ quantity: 1, price: 40 },
{ quantity: 2, price: 10 },
{ quantity: 1, price: 10 } ]
const reducer = (accumulator, currentValue) => {
var a = accumulator.quantity * accumulator.price;
var b = currentValue.quantity * currentValue.price;
return a + b;
}
console.log(arr.reduce(reducer)); // sum if array contains 2 objects, NaN otherwise.
let arr = [
{ quantity: 1, price: 30 },
{ quantity: 1, price: 40 },
{ quantity: 2, price: 10 },
{ quantity: 1, price: 10 }
]
let reducer = (acc, cur) => {
return acc + (Number(cur.quantity) * Number(cur.price));
};
console.log(arr.reduce(reducer, 0));
// 100
Your reducer function seems to be wrong. Accumulator no longer has any parameters to it, since well, it accumulates - its an integer.
Also, set a initial value for your accumulator to start accumulating from, as shown in the reduce function, second parameter input
arr = [ { quantity: 1, price: 30 },
{ quantity: 1, price: 40 },
{ quantity: 2, price: 10 },
{ quantity: 1, price: 10 } ]
const reducer = (accumulator, currentValue) {
return accumulator + (currentValue.quantity * accumulator.price);
}
console.log(arr.reduce(reducer, 0 ));
you can simply say
arr = [ { quantity: 1, price: 30 },
{ quantity: 1, price: 40 },
{ quantity: 2, price: 10 },
{ quantity: 1, price: 10 } ]
const total = arr.reduce((total,item)=>{
total += item.quantity * item.price;
return total
},0)

How to scan through objects that are inside object. [JavaScript]

I am making a barcode scanner for my school project but i am stuck. I dont know how to scan through this object. I have this object with objects inside, and I need to scan through each object inside storage variable to check its barcode.
var storage = {
bolts: {
barcode: 57263144,
price: 0.5,
name: 'Plain Brackets',
stock: 25,
},
brackets: {
barcode: 13245627,
price: 0.2,
name: '100mm Bolts',
stock: 2,
},
}
I have a variable called barcode, and I need to test this variable if its the same like one of these. I tried using
for (var key in storage){
if (storage[key].barcode === barcode){
}
}
I would like the most simple way to do that.
Use Object.keys:
Object.keys(obj).forEach(function(key) {
console.log(key, obj[key]);
});
Below is the example:
var storage = {
"bolts": {
barcode: 57263144,
price: 0.5,
name: 'Plain Brackets',
stock: 25,
},
"brackets": {
barcode: 13245627,
price: 0.2,
name: '100mm Bolts',
stock: 2,
}
}
var barcode = 57263144;
Object.keys(storage).forEach(function(key) {
if(storage[key].barcode === barcode) { console.log("do something")}
});
A Fiddle:
https://jsfiddle.net/spechackers/34bhthza/
Use the recursive function to verify if exist more nodes in the objects, example:
const complexObj = {
name: "nobody",
address: { number: 22, moreNumbers: [1,2,3,4,5] },
colors: ["green", "red"],
numbersAgain: { first: 1, second: 4 }
};
function scanObj(obj){
for (let i in obj) {
/*
*Do some verificatio, example:
*I'd like to verify all numbers and if the numbers is greater than 3:
*/
if(typeof obj[i] == "number" && obj[i] > 3){ console.log(obj[i]); }
if (typeof obj[i] === "object") {
scanObj(obj[i])
}
}
}
//call the method
scanObj(complexObj);
Output: 22 4 5 4

Building multi level menu using nodejs

I currently have the following data in my database
The Mongo database stores like this
id parent
1 0
2 0
3 1
4 1
5 2
6 2
7 2
30 3
31 3
70 7
71 7
Now I want the output in a single javascript array like so using nodejs
[
{id:1,sub:[
{id:3, sub:[{id:30},{id:31}]},
{id:4,sub:[]}
]
},
{id:2,sub:[
{id:5,sub: []},
{id:6,sub: []},
{id:7,sub: [{id:70}, {id:71}]}
]
}
]
The purpose of this is basically to output the category in a megamenu.
The following example shows a way to do what you want.
// Example data from the question
var nodes = [
{ id: 1, parent: 0 },
{ id: 2, parent: 0 },
{ id: 3, parent: 1 },
{ id: 4, parent: 1 },
{ id: 5, parent: 2 },
{ id: 6, parent: 2 },
{ id: 7, parent: 2 },
{ id: 30, parent: 3 },
{ id: 31, parent: 3 },
{ id: 70, parent: 7 },
{ id: 71, parent: 7 }
];
// We construct `t`, the array of parents, so that `t[i] === x` means that `x`
// is the parent of `i`
var t = [];
for (var i = 0; i < nodes.length; i++) {
t[nodes[i].id] = nodes[i].parent;
}
// `t` represents the array of parents
// `c` represents the parent whose children should be put in the outputted array
function f(t, c) {
// The output structure
var a = [];
// We loop through all the nodes to fill `a`
for (var i = 0; i < t.length; i++) {
// If the node has the parent `c`
if (t[i] === c) {
// Create an object with the `id` and `sub` properties and push it
// to the `a` array
a.push({
id: i,
// The `sub` property's value is generated recursively
sub: f(t, i)
});
}
}
// Finish by returning the `a` array
return a;
}
// Print the outputted array in a pretty way
// We call the `f` function with the 0 parameter because 0 is the parent of the
// nodes that should be directly put in the returned array
alert(JSON.stringify(f(t, 0)));
On Node.js 0.12.13 running this code instead of the alert at the end of the above snippet:
var util = require('util');
console.log(util.inspect(f(t, 0), {
colors: true,
depth: null
}));
prints the following:
[ { id: 1,
sub:
[ { id: 3, sub: [ { id: 30, sub: [] }, { id: 31, sub: [] } ] },
{ id: 4, sub: [] } ] },
{ id: 2,
sub:
[ { id: 5, sub: [] },
{ id: 6, sub: [] },
{ id: 7, sub: [ { id: 70, sub: [] }, { id: 71, sub: [] } ] } ] } ]
which I think is what you want.
I also read this page where another solution, possibly more efficient, is described.

How to get the ID of an inserted or updated record in Sequelize upsert?

i need to get the id for the inserted/updated record when using .upsert() in sequelize.
right now .upsert() returns a boolean indicating whether the row was created or updated.
return db.VenueAddress.upsert({
addressId:address.addressId,
venueId: venue.venueId,
street: address.street,
zipCode: address.zipCode,
venueAddressDeletedAt: null
}).then(function(test){
//test returned here as true or false how can i get the inserted id here so i can insert data in other tables using this new id?
});
I don't think that returning the upserted record was available when the OP asked this question, but it has since been implemented with this PR. As of Sequelize v4.32.1, you can pass a boolean returning as a query param to select between returning an array with the record and a boolean, or just a boolean indicating whether or not a new record was created.
You do still need to provide the id of the record you want to upsert or a new record will be created.
For example:
const [record, created] = await Model.upsert(
{ id: 1, name: 'foo' }, // Record to upsert
{ returning: true } // Return upserted record
);
I wanted upsert to return the created or updated object. It doesn't because only PGSQL supports it directly, apparently.
So I created a naive implementation that will - probably in a non-performant way, and possibly with all sorts of race conditions, do that:
Sequelize.Model.prototype.findCreateUpdate = function(findWhereMap, newValuesMap) {
return this.findOrCreate({
where: findWhereMap,
defaults: findWhereMap
})
.spread(function(newObj, created) {
// set:
for(var key in newValuesMap) {
newObj[key] = newValuesMap[key];
}
return newObj.save();
});
};
Usage when trying to create/update a move in a game (contrived example alert!):
models.Game
.findOne({where: {gameId: gameId}})
.then(function(game) {
return db.Move.findCreateUpdate(
{gameId: gameId, moveNum: game.moveNum+1},
{startPos: 'kr4', endPos: 'Kp2'}
);
});
This is what worked for me:
Model.upsert({
title:your title,
desc:your description,
location:your locations
}).then(function (test) {
if(test){
res.status(200);
res.send("Successfully stored");
}else{
res.status(200);
res.send("Successfully inserted");
}
})
It will check db to find based on your primary key. If it finds then, it will update the data otherwise it will create a new row/insert into a new row.
i know this is an old post, but in case this helps anyone
const upsert = async (model: any, values: any, condition: any): Promise<any> => {
const obj = await model.findOne({ where: condition })
if (obj) {
// only do update is value is different from queried object from db
for (var key in values) {
const val = values[key]
if (parseFloat(obj[key]) !== val) {
obj.isUpdatedRecord = true
return obj.update(values)
}
}
obj.isUpdatedRecord = false
return obj
} else {
// insert
const merged = { ...values, ...condition }
return model.create(merged)
}
}
It isn't using upsert, but .bulkCreate has an updateOnDuplicate parameter, which allows you to update certain fields (instead of creating a new row) in the event that the primary key already exists.
MyModel.bulkCreate(
newRows,
{
updateOnDuplicate: ["venueId", ...]
}
)
I believe this returns the resulting objects, and so I think this might enable the functionality you're looking for?
janmeier said:
This is only supported by postgres, so to keep the API consistent across dialects this is not possible.
please see : https://github.com/sequelize/sequelize/issues/3354
I believe my solution is the most up to date with most minimal coding.
const SequelizeModel = require('sequelize/lib/model')
SequelizeModel.upsert = function() {
return this.findOne({
where: arguments[0].where
}).then(obj => {
if(obj) {
obj.update(arguments[0].defaults)
return
}
return this.create(arguments[0].defaults)
})
}
I know this is an old post, but in case this helps anyone...you can get the returned id or any other value in this way based on OP data.
var data = {
addressId:address.addressId,
venueId: venue.venueId,
street: address.street,
zipCode: address.zipCode,
venueAddressDeletedAt: null
}
const result = await db.VenueAddress.upsert(data, { returning: true });
console.log('resulttttttttttttttttt =>', result)
res.status(200).json({ message: 'Your success message', data: result[0].id});
Noticed how I passed { returning: true } and get the value from the result data.
Super old, but if it helps someone:
const [city, created] = await City.upsert({
id: 5,
cityName: "Glasgow",
population: 99999,
});
created is the boolean saying whether the item was created, and in city you have the whole item, where you can get your id.
No need of returning, and this is db agnostic :)
The only solution for SQLite in Sequelize 6.14.0 is to query the inserted row again
I haven't found a solution that works besides a new SELECT query.
It does work in PostgreSQL however.
Presumably, this is because RETURNING was only implemented relatively recently in SQLite 3.35.0 from 2021: https://www.sqlite.org/lang_returning.html and Sequelize doesn't use that version yet.
I've tried both:
Model.upsert with returning: true: did not work on SQLite. BTW, as mentioned at: https://sequelize.org/api/v6/class/src/model.js~model#static-method-upsert returning already defaults to true now, so you don't need to pass it explicitly
Model.bulkCreate with updatOnDuplicate
In both of those cases, some dummy value is returned when the object is present, not the one that is actually modified.
Minimal runnable examples from https://cirosantilli.com/sequelize
update_on_duplicate.js
#!/usr/bin/env node
const assert = require('assert')
const path = require('path')
const { DataTypes, Sequelize } = require('sequelize')
let sequelize
if (process.argv[2] === 'p') {
sequelize = new Sequelize('tmp', undefined, undefined, {
dialect: 'postgres',
host: '/var/run/postgresql',
})
} else {
sequelize = new Sequelize({
dialect: 'sqlite',
storage: 'tmp.sqlite',
})
}
function assertEqual(rows, rowsExpect) {
assert.strictEqual(rows.length, rowsExpect.length)
for (let i = 0; i < rows.length; i++) {
let row = rows[i]
let rowExpect = rowsExpect[i]
for (let key in rowExpect) {
assert.strictEqual(row[key], rowExpect[key])
}
}
}
;(async () => {
const Integer = sequelize.define('Integer',
{
value: {
type: DataTypes.INTEGER,
unique: true, // mandatory
},
name: {
type: DataTypes.STRING,
},
inverse: {
type: DataTypes.INTEGER,
},
},
{
timestamps: false,
}
);
await Integer.sync({ force: true })
await Integer.create({ value: 2, inverse: -2, name: 'two' });
await Integer.create({ value: 3, inverse: -3, name: 'three' });
await Integer.create({ value: 5, inverse: -5, name: 'five' });
let rows
// Initial state.
rows = await Integer.findAll({ order: [['id', 'ASC']]})
assertEqual(rows, [
{ id: 1, value: 2, name: 'two', inverse: -2 },
{ id: 2, value: 3, name: 'three', inverse: -3 },
{ id: 3, value: 5, name: 'five', inverse: -5 },
])
// Update.
rows = await Integer.bulkCreate(
[
{ value: 2, name: 'TWO' },
{ value: 3, name: 'THREE' },
{ value: 7, name: 'SEVEN' },
],
{ updateOnDuplicate: ["name"] }
)
// PostgreSQL runs the desired:
//
// INSERT INTO "Integers" ("id","value","name") VALUES (DEFAULT,2,'TWO'),(DEFAULT,3,'THREE'),(DEFAULT,7,'SEVEN') ON CONFLICT ("value") DO UPDATE SET "name"=EXCLUDED."name" RETURNING "id","value","name","inverse";
//
// but "sequelize": "6.14.0" "sqlite3": "5.0.2" does not use the desired RETURNING which was only added in 3.35.0 2021: https://www.sqlite.org/lang_returning.html
//
// INSERT INTO `Integers` (`id`,`value`,`name`) VALUES (NULL,2,'TWO'),(NULL,3,'THREE'),(NULL,7,'SEVEN') ON CONFLICT (`value`) DO UPDATE SET `name`=EXCLUDED.`name`;
//
// so not sure how it returns any IDs at all, is it just incrementing them manually? In any case, those IDs are
// all wrong as they don't match the final database state, Likely RETURNING will be added at some point.
//
// * https://stackoverflow.com/questions/29063232/sequelize-upsert
// * https://github.com/sequelize/sequelize/issues/7478
// * https://github.com/sequelize/sequelize/issues/12426
// * https://github.com/sequelize/sequelize/issues/3354
if (sequelize.options.dialect === 'postgres') {
assertEqual(rows, [
{ id: 1, value: 2, name: 'TWO', inverse: -2 },
{ id: 2, value: 3, name: 'THREE', inverse: -3 },
// The 6 here seems to be because the new TWO and THREE initially take up dummy rows,
// but are finally restored to final values.
{ id: 6, value: 7, name: 'SEVEN', inverse: null },
])
} else {
assertEqual(rows, [
// These IDs are just completely wrong as mentioned at: https://github.com/sequelize/sequelize/issues/12426
// Will be fixed when one day they use RETURNING.
{ id: 4, value: 2, name: 'TWO', inverse: undefined },
{ id: 5, value: 3, name: 'THREE', inverse: undefined },
{ id: 6, value: 7, name: 'SEVEN', inverse: undefined },
])
}
// Final state.
rows = await Integer.findAll({ order: [['id', 'ASC']]})
assertEqual(rows, [
{ id: 1, value: 2, name: 'TWO', inverse: -2 },
{ id: 2, value: 3, name: 'THREE', inverse: -3 },
{ id: 3, value: 5, name: 'five', inverse: -5 },
{ id: 6, value: 7, name: 'SEVEN', inverse: null },
])
})().finally(() => { return sequelize.close() });
upsert.js
#!/usr/bin/env node
const assert = require('assert')
const path = require('path')
const { DataTypes, Sequelize } = require('sequelize')
let sequelize
if (process.argv[2] === 'p') {
sequelize = new Sequelize('tmp', undefined, undefined, {
dialect: 'postgres',
host: '/var/run/postgresql',
})
} else {
sequelize = new Sequelize({
dialect: 'sqlite',
storage: 'tmp.sqlite',
})
}
function assertEqual(rows, rowsExpect) {
assert.strictEqual(rows.length, rowsExpect.length)
for (let i = 0; i < rows.length; i++) {
let row = rows[i]
let rowExpect = rowsExpect[i]
for (let key in rowExpect) {
assert.strictEqual(row[key], rowExpect[key])
}
}
}
;(async () => {
const Integer = sequelize.define('Integer',
{
value: {
type: DataTypes.INTEGER,
unique: true,
},
name: {
type: DataTypes.STRING,
},
inverse: {
type: DataTypes.INTEGER,
},
},
{
timestamps: false,
}
);
await Integer.sync({ force: true })
await Integer.create({ value: 2, inverse: -2, name: 'two' });
await Integer.create({ value: 3, inverse: -3, name: 'three' });
await Integer.create({ value: 5, inverse: -5, name: 'five' });
let rows
// Initial state.
rows = await Integer.findAll({ order: [['id', 'ASC']]})
assertEqual(rows, [
{ id: 1, value: 2, name: 'two', inverse: -2 },
{ id: 2, value: 3, name: 'three', inverse: -3 },
{ id: 3, value: 5, name: 'five', inverse: -5 },
])
// Update.
rows = [(await Integer.upsert({ value: 2, name: 'TWO' }))[0]]
if (sequelize.options.dialect === 'postgres') {
assertEqual(rows, [
{ id: 1, value: 2, name: 'TWO', inverse: -2 },
])
} else {
// Unexpected ID returned due to the lack of RETURNING, we wanted it to be 1.
assertEqual(rows, [
{ id: 3, value: 2, name: 'TWO', inverse: undefined },
])
}
rows = [(await Integer.upsert({ value: 3, name: 'THREE' }))[0]]
if (sequelize.options.dialect === 'postgres') {
assertEqual(rows, [
{ id: 2, value: 3, name: 'THREE', inverse: -3 },
])
} else {
assertEqual(rows, [
{ id: 3, value: 3, name: 'THREE', inverse: undefined },
])
}
rows = [(await Integer.upsert({ value: 7, name: 'SEVEN' }))[0]]
if (sequelize.options.dialect === 'postgres') {
assertEqual(rows, [
{ id: 6, value: 7, name: 'SEVEN', inverse: null },
])
} else {
assertEqual(rows, [
{ id: 6, value: 7, name: 'SEVEN', inverse: undefined },
])
}
// Final state.
rows = await Integer.findAll({ order: [['value', 'ASC']]})
assertEqual(rows, [
{ id: 1, value: 2, name: 'TWO', inverse: -2 },
{ id: 2, value: 3, name: 'THREE', inverse: -3 },
{ id: 3, value: 5, name: 'five', inverse: -5 },
{ id: 6, value: 7, name: 'SEVEN', inverse: null },
])
})().finally(() => { return sequelize.close() });
package.json
{
"name": "tmp",
"private": true,
"version": "1.0.0",
"dependencies": {
"pg": "8.5.1",
"pg-hstore": "2.3.3",
"sequelize": "6.14.0",
"sql-formatter": "4.0.2",
"sqlite3": "5.0.2"
}
}
In both of those examples, we see that PostgreSQL runs the desired:
INSERT INTO "Integers" ("id","value","name") VALUES (DEFAULT,2,'TWO'),(DEFAULT,3,'THREE'),(DEFAULT,7,'SEVEN') ON CONFLICT ("value") DO UPDATE SET "name"=EXCLUDED."name" RETURNING "id","value","name","inverse";
which works due to RETURNING, but sequelize does not use the desired RETURNING
INSERT INTO `Integers` (`id`,`value`,`name`) VALUES (NULL,2,'TWO'),(NULL,3,'THREE'),(NULL,7,'SEVEN') ON CONFLICT (`value`) DO UPDATE SET `name`=EXCLUDED.`name`;
Tested on Ubuntu 21.10, PostgreSQL 13.5.
Which I myself resolved as follows:
return db.VenueAddress.upsert({
addressId:address.addressId,
venueId: venue.venueId,
street: address.street,
zipCode: address.zipCode,
venueAddressDeletedAt: null
},{individualHooks: true}).then(function(test){
// note individualHooks
});

Resources