update可以幫助我們更新object
內的property
及link
。
我們繼續使用[Day03]中定義的schema
:
type User {
required name: str;
multi followers: User;
}
type Article {
required title: str;
required author: User;
}
執行下列query建立兩個Article object
及四個User object
。
insert Article {
title:= "first article",
author:= (insert User {name:= "John"})
};
insert Article {
title:= "second article",
author:= (insert User {name:= "Jeff"})
};
for name in {"Tom", "Cathy"}
union (insert User {name:= name});
以下我將以Cathy
、John
、Tom
與Jeff
來簡單稱呼其name property
分別為「"Cathy"」、「"John"」、「"Tom"」與「"Jeff"」的User object
。
假設我們現在想將Cathy
加入到John
的multi followers link
中,可以這麼寫:
update User filter .name="John"
set {
followers+= (select detached User filter .name="Cathy")
};
我們可以使用+=
將所選取的EdgeDBSet
加入multi followers link
,並使用-=
將所選取的EdgeDBSet
移出multi followers link
。
這裡需注意當所選取的object type
與內部link
的object type
相同時,會有scope的問題,這時候大多需要使用detached。
這裡我們update
的對象是User object
中,其name property
為「"John"」所形成的EdgeDBSet
,也就是說在set
的區塊內,User
將會被視為這個新EdgeDBSet
,而不是原先那個含有所有User object
的EdgeDBSet
。
也就是說,如果將query寫為下面這樣:
update User filter .name="John"
set {
followers+= (select User filter .name="Cathy")
};
其multi followers link
將不會改變,因為(select User filter .name="Cathy")
是一個空的EdgeDBSet
。
這點可以透過下面query來確認:
select User{**} filter .name="John";
{
default::User {
id: 67fd98c6-3f5b-11ef-9acb-ff0f4fd955f6,
name: 'John',
followers: {}
}
}
這裡可以看出,沒有任何User object
被加入到John
的multi followers link
中。
如果無法理解detached
的適用時機的話,使用with
會是一個不錯的query寫法。在with
中,EdgeDB會自動幫您做detached
,所以即使選擇的object type
與update
的object type
一樣,也不需要擔心。
所以原先query可以改寫成:
with cathy:= (select User filter .name="Cathy")
update User filter .name="John"
set {
followers+= cathy
};
或是:
with john:= (select User filter .name="John"),
cathy:= (select User filter .name="Cathy")
update john
set {
followers+= cathy
};
scopes
與detached
是一個相當常犯的錯誤,需多加小心。
假設現在Cathy
除了想要追蹤John
外,也想追蹤Jeff
跟Tom
,我們可以這樣寫:
with names:= {"Jeff", "Tom"},
cathy:= (select User filter .name="Cathy")
for name in names
union (
update User filter .name=name
set {
followers+= cathy
}
);
或是省略union
:
with names:= {"Jeff", "Tom"},
cathy:= (select User filter .name="Cathy")
for name in names
update User filter .name=name
set {
followers+= cathy
};
當然,編寫EdgeQL
可以依靠自己對database
內object
的熟悉程度,以較簡單的語法,來寫出針對當前情況有同等效果的query,例如:
with cathy:= (select User filter .name="Cathy")
update User filter .name not in {"John", "Cathy"}
set {
followers+= cathy
};