【Foon】开发了一个能在Firestore中自动管理GAE Memcache的库
简而言之
尽管本来我应该在开发网络应用程序,但错拿编写了一个库而浪费了时间,我感到后悔(已公开)。
Foon
https://github.com/brbranch/foon
Foon
https://github.com/brbranch/foon
Foon的概述
在Go语言中,虽然有一些可以管理GAE Memcache的DataStore库(比如说goon非常有名),但是在Firestore的原生模式下,我没有找到合适的库来进行协作,所以我自己创建了一个。因此,我在这里简要介绍它的用法。
在Firestore中,由于它是实时数据库,我觉得没有必要使用多分库。因为如果想要利用它的功能,那么Memcache可能会成为一个干扰因素。但是如果不使用这个功能,为了节约成本,我还是希望能够与之协同工作。(但事实上,只需要在Firestore的数据库模式下进行操作就可以了…)
機能の概要
Create / Read / Update / Deleteした際、そのデータをMemcacheにも登録します。
また、Readする際にはMemcacheに存在するかどうか確認し、あればそれを返却します。キャッシュはQueryの結果も保持します。ただQuery結果は、内包される可能性のあるデータが更新されたタイミングで全て破棄されるので、ダーティリードやファントムリードのようなのは起きない(はず)。
我们在内部封装了Firestore原生API (Godoc),目前已经实现了以下API。
截至2019年7月的对应功能版本0.9.
-
- Put / PutMulti (追加 or 更新)
-
- Insert / InsertMulti (追加 or 重複の場合エラー)
-
- Get / GetMulti / GetAll / GetByQuery (それぞれキャッシュ使わないメソッドもあり)
-
- RunInTransaction
-
- Batch
- Delete
※ GetByQueryは現在一部のみ対応
未対応
-
- DeleteMulti
-
- Firestore API の Updateに該当する機能
-
- GetByQueryの一部検索方法
-
- CollectionGroupでの検索
-
- ぼくがまだよくわかってないFirestore API
-
- リアルタイム通知系
- IDを数値でも管理したいなって思ってたり思ってなかったり
收藏的定义
通过添加 foon 标签,将其与 Firestore 的 Collection 或 Document 相关联。
在下面的示例中,User 文档将存储在名为 Users 的集合中。
type User struct {
__kind string `foon:"collection,Users"`
ID string `foon:"id"`
Name string `firestore:"name"`
CreatedAt time.Time `foon:"createdAt" firestore:"createdAt"`
UpdatedAt time.Time `foon:"updatedAt" firestore:"updatedAt"`
}
foon:”id” は識別するために必須です。
子集合的定义
Firestoreでは、Documentの中にもSubCollectionを定義できます。
それは、Foonでは以下のように定義します。
type Device struct {
__kind string `foon:"collection,Devices"`
ID string `foon:"id"`
Parent *foon.Key `foon:"parent"`
DeviceName string `firestore:"deviceName"`
}
foon: “id” 是必要的以进行标识。
执行
添加新的
像这样,可以像goon一样进行。使用insert时,如果ID重复,则会出现错误。
f := foon.Must(appEngineContext)
user := &User{ ID: "user0001", Name: "username01" }
if err := f.Insert(user); err != nil {
// エラー処理
}
// ID指定なしの新規追加もできます。その場合、自動でランダムな文字列が払い出され、セットされます
user := &User{ Name: "username01" }
if err := f.Insert(user); err != nil {
// エラー処理
}
// まとめて追加
users := []*User{
{ Name: "user001" }
{ ID: "user01", Name: "user002"}
}
if err := f.InsertMulti(&users); err != nil {
// エラー処理
}
更新 –
如果有更新的情况下,如果ID重复,则会进行覆盖。
f := foon.Must(appEngineContext)
user := &User{ ID: "user0001", Name: "username01" }
if err := f.Put(user); err != nil {
// エラー処理
}
// ID指定なしの新規追加もできます。その場合、自動でランダムな文字列が払い出され、セットされます
user := &User{ Name: "username01" }
if err := f.Put(user); err != nil {
// エラー処理
}
// まとめて追加
users := []*User{
{ Name: "user001" }
{ ID: "user01", Name: "user002"}
}
if err := f.PutMulti(&users); err != nil {
// エラー処理
}
阅读
在读取的情况下,使用Get / GetMulti时需要指定ID。
user := &User{ ID: "user001" }
f := foon.Must(appEngineContext)
if err := f.Get(user); err != nil {
// エラー処理
}
// user内にデータは格納できてる
users := []*User{
{ ID: "user001" }, { ID: "user002" }
}
if err := f.GetMulti(&users); err != nil {
// エラー処理
}
// Usersコレクションの全てのUserドキュメントを取得
users := []*User{}
if err := f.GetAll(foon.NewKey(&User{}), &users); err != nil {
// エラー処理
}
// クエリで取得
users := []*User{}
conditions := foon.NewConditions().Where("name" , "==" , "user001").Limit(3)
if err := f.GetByQuery(foon.NewKey(&User{}), &users, conditions); err != nil {
// エラー処理
}
删除
user := &User{ ID: "user001" }
f := foon.Must(appEngineContext)
if err := f.Delete(user); err != nil {
// エラー処理
}
交易
方法基本上是一样的。使用传入的参数foon进行读写操作。
※ 在事务中不会读取缓存。但是,写操作会进行,所以可能会发生脏读等(正在考虑怎么做…最后成功后可能需要将所有内容写入缓存之类的操作吧)
f := foon.Must(appEngineContext)
err := f.RunInTransaction(func(fn *Foon) error {
// 内部処理
// Firestoreの制約で、書き込みを行った後読み込みを行うとエラーになるよ
});
批处理
在仅仅进行写入操作时,这是一种简单且原子化的方式(例如PutMulti等操作在内部也使用了这种方式)。
f := foon.Must(appEngineContext)
batch , _ := f.Batch()
batch.Create(&User{ ID: "user001" })
batch.Create(&User{ ID: "user002" })
batch.Delete(&User{ ID: "user003" })
if err := batch.Commit(); err != nil {
// エラー処理
}
サブコレクションの扱い
FirestoreにはDocumentにもCollectionを持たせることができます。
これは、Datastore風にいうとAncestorの言い方が変わっただけで、実際はあんま変わらないです。
というわけで、Foonでは Parent として表現をしてます。
如果想获取以下数据中的 ID: Device002,
Users (collection)
├ User001 (Document)
└ User002 (Document)
└ Devices (Collection)
├ Device001 (Document)
├ Device002 (Document)
︰
以下のようにできます。要は foon:”parent” で定義した箇所に、親となるDocumentのKeyを入れることで表現できます。
user := &User{ ID: "User002" }
f := foon.Must(appEngineContext)
parentKey := foon.NewKey(user)
device := &Device{ ID: "Device002" , Parent: parentKey }
// 取得
if err := f.Get(device); err != nil {
// エラー処理
}
device.DeviceName = "iPhoneX"
// 更新
if err := f.Put(device); err != nil {
// エラー処理
}
// User002に新規にデバイスを登録
newDevice := &Device{ Parent: parentKey }
if err := f.Insert(newDevice); err != nil {
// エラー処理
}
如果您想访问Devices的收藏并发出查询,方法也是相同的。
user := &User{ ID: "User002" }
f := foon.Must(appEngineContext)
parentKey := foon.NewKey(user)
deviceCollectionKey := foon.NewKey(&Device{ Parent: parentKey})
devices := []*Device{}
if err := f.GetAll(deviceCollectionKey, &users); err != nil {
// エラー処理
}
概括
让我们继续制作网络应用程序吧…
但是,我希望参考这些地方并且将其更加正式地发布出来的热情也在燃烧着…
参考: 仅需提供一种选择,将以下内容以中文作本地化改写。
Firestore(GoDoc)
https://godoc.org/cloud.google.com/go/firestore
Firestore(GoDoc)
https://godoc.org/cloud.google.com/go/firestore