Kotlinデータクラスがあります
data class Client(
val name: String = "",
val email: String = "",
val phone: String ="") {
constructor():this("","","")}
Firestoreでデータをクラスに適切に設定していますが、ドキュメントIDをドキュメント自体に設定せずにデータIDを取得する方法を見つけようとして途方に暮れています。これは可能ですか?
はい、DocumentSnapshot
を使用して、保存せずにidを取得することができます。ここで完全な例を構築してみます。
IDを保持する一般的なModelクラスを作成しました:
_@IgnoreExtraProperties
public class Model {
@Exclude
public String id;
public <T extends Model> T withId(@NonNull final String id) {
this.id = id;
return (T) this;
}
}
_
次に、任意のモデルで拡張し、何も実装する必要はありません。
_public class Client extends Model
_
ここにクライアントのリストがある場合、リストを照会して_age == 20
_を持つクライアントのみを取得しようとします:
_clients.whereEqualTo("age", 20)
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (DocumentSnapshot documentSnapshot : task.getResult().getDocuments()) {
// here you can get the id.
Client client = document.toObject(client.class).withId(document.getId());
// you can apply your actions...
}
} else {
}
}
});
_
また、EventListener
を使用している場合は、次のようなIDも取得できます。
_clients.addSnapshotListener(new EventListener<QuerySnapshot>() {
@Override
public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
for (DocumentChange change : documentSnapshots.getDocumentChanges()) {
// here you can get the id.
Client client = document.toObject(client.class).withId(document.getId());
// you can apply your actions...
}
}
});
_
documentSnapshot.getId())
は、ドキュメントにIDを保存せずに、コレクション内のドキュメントのIDを取得します。
モデルを使用しても、モデルを編集することはできません。また、_@IgnoreExtraProperties
_を使用することを忘れないでください
@iCediCeのソリューションを改善し、DocumentSnapshotおよびQuerySnapshotにメソッドを追加しました。
interface HasId {
var id : String
}
inline fun <reified T : HasId> DocumentSnapshot.toObjectWithId(): T {
return this.toObject(T::class.Java)!!.also {
it.id = this.id
}
}
inline fun <reified T : HasId> QuerySnapshot.toObjectsWithId(): List<T> {
return this.documents.map {
it.toObjectWithId<T>()
}
}
そして使用法:
data class User(
@get:Exclude
override var id: String,
...
): HasId
val user = documentSnapshot.toObjectWithId<User>()
val users = querySnapshot.toObjectsWithId<User>()
ここに私が問題を解決した方法があります。
data class Client(
val name: String = "",
val email: String = "",
val phone: String ="",
@get:Exclude var id: String = "") {
constructor():this("","","")
}
IDで@get:Excludeを使用して、保存時にIDがFirestoreに送信されないようにし、クライアントのリストを取得するときに実行します:
snapshot.documents.mapTo(list) {
var obj = it.toObject(Client::class.Java)
obj.id = it.id
obj
}
新しいオブジェクトのIDをドキュメント参照のIDに設定します。
QueryDocumentSnapshotに次のような拡張メソッドを作成することで解決しました。
_inline fun <reified T : HasId>QueryDocumentSnapshot.toObjectWithId(): T {
val model = this.toObject(T::class.Java)
model.id = this.id
return model
}
_
これで、次のようにマップできます(見た目はきれいできれいです):myModelWithId = it.toObjectWithId<MyModel>()
これが機能するために、モデルで実装する必要がある単純なhasIdインターフェイスを作成しました。
_interface HasId{
var id : String
}
@IgnoreExtraProperties
data class MyModel(
@get:Exclude override var id : String = "",
val data : String = "",
): Serializable, HasId
_
素晴らしいソリューション。 Firestoreがモデルに注釈を追加してこの問題を解決する方法を考案したようです。
できること:
_@DocumentId val documentId: String
_
そして、FirestoreはtoObject
またはtoObjects
を呼び出すときにそのフィールドを生成します。 Firestoreでドキュメントを.set()
すると、このフィールドは除外されます。
FirebaseでIDを取得してから、Firebaseで作成する前にオブジェクトのフィールドとして設定します。
override fun addTodo(todo: Todo) =
Completable.fromAction {
val id = firestore
.collection(COLLECTION_TODOS)
.document()
.id
val newTodo = todo.copy(id = id)
firestore
.collection(COLLECTION_TODOS)
.document(id)
.set(newTodo)
}