如何使用kotlin数据类获取Firestore文档的文档ID

时间:2017-10-28 22:23:45

标签: android firebase kotlin google-cloud-firestore

我有kotlin数据类

data class Client(

    val name: String = "",
    val email: String = "",
    val phone: String ="") {
constructor():this("","","")}

我让firestore将数据填充到类中,但是我不知道如何将文档id放入数据类而不必在文档本身中设置它。这可能吗?

6 个答案:

答案 0 :(得分:19)

是的,使用DocumentSnapshot可以在不存储ID的情况下获取ID。我将尝试在这里建立完整的例子。

我创建了一个通用的Model类来保存id:

@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

答案 1 :(得分:6)

以下是我解决问题的方法。

data class Client(
    val name: String = "",
    val email: String = "",
    val phone: String ="",
    @get:Exclude var id: String = "") {
constructor():this("","","")
}

我使用@get:在id上排除以确保在保存时不会将id发送到Firestore,然后在获取客户端列表时执行:

snapshot.documents.mapTo(list) {
            var obj = it.toObject(Client::class.java)
            obj.id = it.id
            obj
        }

将新对象的id设置为文档引用的id。

答案 2 :(得分:5)

我通过在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

答案 3 :(得分:4)

我刚刚改进了@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>()

答案 4 :(得分:3)

很好的解决方案。看起来Firestore想出了一种向模型添加注释来解决此问题的方法。

您可以这样做:

@DocumentId val documentId: String

然后,Firestore将在调用toObjecttoObjects时生成该字段。当您.set()在Firestore中的文档时,它将排除此字段。

答案 5 :(得分:0)

在Firebase中创建ID之前,我只是从Firestore中获取ID并将其设置为对象上的字段:

    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)
    }