Graph upserts
オブジェクトグラフを元に、データベース上のレコードの登録・更新・削除を行う機能。
使用例
以下のようなデータがデータベースに登録されているとします。
[ Project {
id: 53,
name: 'project1',
ownerId: null,
members:
[ User {
id: 48,
name: 'hoge',
email: 'hoge@example.com',
tasks:
[ Task {
id: 15,
name: 'hoge\'s task1',
description: null,
assignedTo: 48,
projectId: 53,
deadline: null,
createdAt: 2018-08-19T13:03:57.761Z,
updatedAt: 2018-08-19T13:03:57.761Z },
Task {
id: 16,
name: 'hoge\'s task2',
description: null,
assignedTo: 48,
projectId: 53,
deadline: null,
createdAt: 2018-08-19T13:03:57.761Z,
updatedAt: 2018-08-19T13:03:57.761Z } ] },
User { id: 49, name: 'piyo', email: 'piyo@example.com', tasks: [] } ] },
Project {
id: 54,
name: 'project2',
ownerId: null,
members:
[ User {
id: 48,
name: 'hoge',
email: 'hoge@example.com',
tasks:
[ Task {
id: 15,
name: 'hoge\'s task1',
description: null,
assignedTo: 48,
projectId: 53,
deadline: null,
createdAt: 2018-08-19T13:03:57.761Z,
updatedAt: 2018-08-19T13:03:57.761Z },
Task {
id: 16,
name: 'hoge\'s task2',
description: null,
assignedTo: 48,
projectId: 53,
deadline: null,
createdAt: 2018-08-19T13:03:57.761Z,
updatedAt: 2018-08-19T13:03:57.761Z } ] },
User {
id: 50,
name: 'fuga',
email: 'fuga@example.com',
tasks:
[ Task {
id: 17,
name: 'fuga\'s task1',
description: null,
assignedTo: 50,
projectId: 54,
deadline: 2018-09-30T15:00:00.000Z,
createdAt: 2018-08-19T13:03:57.761Z,
updatedAt: 2018-08-19T13:03:57.761Z } ] } ] } ]
const { transaction } = require('objection');
const { inspect } = require('util');
await transaction(Project.knex(), async (trx) => {
const projects = await Project.query(trx)
.upsertGraph([
{
id: 53,
members: [
{
id: 48,
name: 'hoge',
tasks: [
// idが15のtaskを更新
{
id: 15,
name: 'hoge\'s task1',
description: 'hogeのタスク',
assignedTo: 48
}
// idが16のtaskは指定されていないため、データベース上から関連が削除されます。
]
},
{
// idを持っていないため、データベースに新しいレコードが作成される。
'#id': 'hogepiyo',
name: 'hogepiyo',
email: 'hogepiyo@example.com',
tasks: [
{
// idを持っていないため、データベースに新しいレコードが作成される。
name: "#ref{hogepiyo.name}'s task",
projectId: 53
}
]
}
]
},
{
// idを持っていないため、データベースに新しいレコードが作成される。
name: 'project3',
members: [
{ id: 48 },
{ '#ref': 'hogepiyo' }
]
}
], {
relate: ['members', 'members.tasks'],
unrelate: ['members']
});
console.log(inspect(projects, { depth: 5 }));
// [ Project {
// id: 53,
// members:
// [ User {
// id: 48,
// name: 'hoge',
// tasks:
// [ Task {
// id: 15,
// name: 'hoge\'s task1',
// description: 'hogeのタスク',
// assignedTo: 48 } ] },
// User {
// name: 'hogepiyo',
// email: 'hogepiyo@example.com',
// tasks:
// [ Task {
// name: 'hogepiyo\'s task',
// projectId: 53,
// assignedTo: 54,
// id: 20 } ],
// id: 54 } ] },
// Project {
// name: 'project3',
// members:
// [ User { id: 48 },
// User { name: 'hogepiyo', email: 'hogepiyo@example.com', id: 54 } ],
// id: 58 } ]
});
上記を実行すると、データベース上のデータは、以下のような状態になります。
[ Project {
id: 53,
name: 'project1',
ownerId: null,
members:
[ User {
id: 48,
name: 'hoge',
email: 'hoge@example.com',
tasks:
[ Task {
id: 15,
name: 'hoge\'s task1',
description: 'hogeのタスク',
assignedTo: 48,
projectId: 53,
deadline: null,
createdAt: 2018-08-19T13:03:57.761Z,
updatedAt: 2018-08-19T13:03:57.761Z } ] },
User {
id: 54,
name: 'hogepiyo',
email: 'hogepiyo@example.com',
tasks:
[ Task {
id: 20,
name: 'hogepiyo\'s task',
description: null,
assignedTo: 54,
projectId: 53,
deadline: null,
createdAt: 2018-08-19T13:12:08.443Z,
updatedAt: 2018-08-19T13:12:08.443Z } ] } ] },
Project {
id: 54,
name: 'project2',
ownerId: null,
members:
[ User {
id: 48,
name: 'hoge',
email: 'hoge@example.com',
tasks:
[ Task {
id: 15,
name: 'hoge\'s task1',
description: 'hogeのタスク',
assignedTo: 48,
projectId: 53,
deadline: null,
createdAt: 2018-08-19T13:03:57.761Z,
updatedAt: 2018-08-19T13:03:57.761Z } ] },
User {
id: 50,
name: 'fuga',
email: 'fuga@example.com',
tasks:
[ Task {
id: 17,
name: 'fuga\'s task1',
description: null,
assignedTo: 50,
projectId: 54,
deadline: 2018-09-30T15:00:00.000Z,
createdAt: 2018-08-19T13:03:57.761Z,
updatedAt: 2018-08-19T13:03:57.761Z } ] } ] },
Project {
id: 58,
name: 'project3',
ownerId: null,
members:
[ User {
id: 48,
name: 'hoge',
email: 'hoge@example.com',
tasks:
[ Task {
id: 15,
name: 'hoge\'s task1',
description: 'hogeのタスク',
assignedTo: 48,
projectId: 53,
deadline: null,
createdAt: 2018-08-19T13:03:57.761Z,
updatedAt: 2018-08-19T13:03:57.761Z } ] },
User {
id: 54,
name: 'hogepiyo',
email: 'hogepiyo@example.com',
tasks:
[ Task {
id: 20,
name: 'hogepiyo\'s task',
description: null,
assignedTo: 54,
projectId: 53,
deadline: null,
createdAt: 2018-08-19T13:12:08.443Z,
updatedAt: 2018-08-19T13:12:08.443Z } ] } ] } ]
upsertGraphメソッドはデフォルトで、以下のように動作します。
- グラフ中のidを持たないオブジェクトは、データベースの対応するテーブルに新しいレコードとして登録される。
- グラフ中のidを持つオブジェクトは、データベースの対応するレコードが更新される。
- データベース上には関連が存在するが、グラフ中に現れなかったオブジェクトは、データベースからレコードが削除される。
内部的にinsertGraphメソッドを利用しているため、#id
や#ref
の機能を利用することができます。
上記の例では、第2引数でrelateおよびunrelateオプションを指定することで、デフォルトの挙動を変更しています。
{
// membersおよびtasksについては、データベース上に存在するレコードに対する関連を作成できるようにする
relate: ['members', 'members.tasks'],
// membersについては、グラフ中に登場しないオブジェクトがあった際は、データベース上のレコードは削除せず、関連の削除のみを行う(usersテーブルからはレコードを削除せず、joinテーブルのみからレコードを削除する)
unrelate: ['members']
}
insertGraph同様、デフォルトではatomicではないので、transactionと併用する必要があります。
参考