考慮schema如下:
type User {
required name: str;
multi followers: User;
}
type Article {
required title: str;
required author: User;
}
本日的學習目標是希望透過前面幾天的說明,大家能獨自完成下面這四道練習:
Q1:建立三個User object
,Jeff
、Tom
及Cathy
,其name property
分別為「"Jeff"」、「"Tom"」及「"Cathy"」。
Q2:將每個User object
的multi followers link
設定為除了自己以外的兩個User object
。
Q3:將Cathy
自每個User object
的multi followers link
中移除。
Q4:建立三個Article object
,其title property
分別為「"title1"」、「"title2"」、及「"title3"」,其author link
為三個User object
中隨機選取一位。
以下我們提供兩個方法作為參考答案。方法1是基礎的操作,而方法2借鑒方法1的寫法,並搭配for-loop
使得query更加結構化。
insert
User object
首先建立三個User object
,並指定其name property
:
insert User {name:= "Jeff"};
insert User {name:= "Tom"};
insert User {name:="Cathy"};
此時三個User object
成功建立。
select User {name};
{
default::User {name: 'Jeff'},
default::User {name: 'Tom'},
default::User {name: 'Cathy'}
}
update
User object
- 加入新User object
至multi followers link
接著update
三個User object
內的multi followers link
:
update User filter .name="Jeff"
set {
multi followers:= (select User filter .name in {"Tom", "Cathy"})
};
update User filter .name="Tom"
set {
multi followers:= (select User filter .name in {"Jeff", "Cathy"})
};
update User filter .name="Cathy"
set {
multi followers:= (select User filter .name in {"Jeff", "Tom"})
};
但我們卻發現multi followers link
並沒有更新,聰明的您看出來問題在哪邊了嗎?
select User {**};
{
default::User {
id: f789868a-4fd2-11ef-8734-db28a46e9f9c,
name: 'Jeff',
followers: {}
},
default::User {
id: f78ca9c8-4fd2-11ef-8734-53dcbb5a15d8,
name: 'Tom',
followers: {}
},
default::User {
id: f78ef002-4fd2-11ef-8734-eb9d204119a7,
name: 'Cathy',
followers: {}
},
}
沒錯,就是關於之前於[Day05]提過的detached
,實務上這是一個非常容易犯錯的地方,需要多加小心。
正確的query可以寫為:
update User filter .name="Jeff"
set {
followers:= (select detached User filter .name in {"Tom", "Cathy"})
};
update User filter .name="Tom"
set {
followers:= (select detached User filter .name in {"Jeff", "Cathy"})
};
update User filter .name="Cathy"
set {
followers:= (select detached User filter .name in {"Jeff", "Tom"})
};
又或者搭配with
寫為:
with jeff:= (select User filter .name="Jeff"),
followers:= (select User filter .name in {"Tom", "Cathy"})
update jeff
set {
followers:= followers
};
with tom:= (select User filter .name="tom"),
followers:= (select User filter .name in {"Jeff", "Cathy"})
update tom
set {
followers:= followers
};
with cathy:= (select User filter .name="Cathy"),
followers:= (select User filter .name in {"Jeff", "Tom"})
update cathy
set {
followers:= followers
};
update
User object
- 自multi followers link
中移除Cathy
這邊利用-=
來移除Cathy
:
with jeff:= (select User filter .name="Jeff"),
cathy:= (select User filter .name="Cathy")
update jeff
set {
followers-= cathy
};
with tom:= (select User filter .name="Tom"),
cathy:= (select User filter .name="Cathy")
update tom
set {
followers-= cathy
};
如果不習慣這樣的寫法,也可以寫成:
with jeff:= (select User filter .name="Jeff"),
cathy:= (select User filter .name="Cathy")
update jeff
set {
followers:= .followers except cathy
};
with tom:= (select User filter .name="Tom"),
cathy:= (select User filter .name="Cathy")
update tom
set {
followers:= .followers except cathy
};
留意這邊使用的是:=
。:=
代表將.followers except cathy
這個set operation
的結果指定給multi followers link
。
insert
Article object
最後建立三個Article object
,並指定其name property
:
insert Article {
title:= "title1",
author:= (select User order by random() limit 1)
};
insert Article {
title:= "title2",
author:= (select User order by random() limit 1)
};
insert Article {
title:= "title3",
author:= (select User order by random() limit 1)
};
這邊我們使用了random()
來隨機產生一個0.0 <= x < 1.0
間的浮點數,並搭配order by
來產生一個隨機的排序,最後再使用了limit 1
來選擇第一個元素。
此時三個Article object
成功建立。
select Article {title, author: {name} };
{
default::Article {title: 'title1', author: default::User {name: 'Cathy'}},
default::Article {title: 'title2', author: default::User {name: 'Cathy'}},
default::Article {title: 'title3', author: default::User {name: 'Tom'}},
}
insert
User object
我們將names
集合為一個EdgeDBSet
,就可以於迴圈中指定User object
的name property
。
with names:= {"Jeff", "Tom", "Cathy"}
for name in names
union (insert User {name:= name});
update
User object
- 加入新User object
至multi followers link
此處我們靈活運用set operation
中的except
來選取除自己外的User object
。
with names:= {"Jeff", "Tom", "Cathy"}
for name in names
union (
with user:= (select User filter .name=name)
update user
set {
followers:= (select User except user)
}
);
update
User object
- 自multi followers link
中移除Cathy
這邊我們使用select User.name
來選取所有User object
的name property
所形成的EdgeDBSet
並使用except
來排除「"Cathy"」這個str
:
with names:= (select User.name except {"Cathy"}),
cathy:= (select User filter .name="Cathy")
for name in names
union (
with user:= (select User filter .name=name)
update user
set {
followers-= cathy
}
);
這種使用.
來選擇object type
的property
或link
十分方便,但初學時容易忘記,這邊特別提醒大家。
insert
Article object
此處我們利用range_unpack
在每個迴圈中取得1, 2, 3,並使用<str>i
將其轉為str
型別後,搭配++
與「"title"」合併。
for i in range_unpack(range(1, 4))
union (
insert Article {
title:= "title" ++ <str>i,
author:= (select User order by random() limit 1)
}
);