【问题标题】:Unable to get Timestamp document field from Firestore无法从 Firestore 获取时间戳文档字段
【发布时间】:2018-10-24 07:18:38
【问题描述】:

从 Firestore 获取数据时,我无法获取时间戳字段。

我的 Room 文档的结构如下:

我正在从 Firestore 获取房间,如下所示。

助手类:

    fun getRooms(userId: String): Task<QuerySnapshot> {
        return FirebaseFirestore.getInstance()
                .collection(KEY_USERS).document(userId)
                .collection(KEY_ROOMS).get()
    }

交互类:

private fun getRooms(): Task<List<Room>> {
    val source = TaskCompletionSource<List<Room>>()
    val listener = OnCompleteListener<QuerySnapshot> {
        if (it.isSuccessful) {
            val roomSnapshots = it.result
            if (!roomSnapshots.isEmpty) {
                val rooms = ArrayList<Room>()
                for (roomSnapshot in roomSnapshots) {
                    rooms.add(Room(roomSnapshot))
                }
                source.setResult(rooms)
            }
        } else {
            source.setException(it.exception!!)
        }
    }
    FirebaseFireStoreHelper.getRooms(mUserId).addOnCompleteListener(listener)
    return source.task
}

我的Room模特班:

class Room(document: DocumentSnapshot) {

    companion object {
        private const val KEY_DATE_CREATED = "dateCreated"
        private const val KEY_TITLE = "title"
    }

    private lateinit var mId: String
    private lateinit var mDateCreated: Date
    private lateinit var mTitle: String

    init {
        if (document.exists()) {
            mId = document.id
            mDateCreated = document.getDate(KEY_DATE_CREATED)!!
            mTitle = document.getString(KEY_TITLE)!!
        }
    }

    fun getId(): String = mId

    fun getDateCreated(): Date? = mDateCreated

    fun getTitle(): String = mTitle

}

问题是document.getDate(KEY_DATE_CREATED) 总是返回null。我尝试使用get(KEY_DATE_CREATED) 和getString(KEY_DATE_CREATED) 只是为了看看我是否可以获得任何价值,但无济于事。

再试几次后,我测试打印出整个对象并能够得到这个:

DocumentSnapshot{
    key=users/kCKkmgLmLGfvbPFK09qyZ5uoyw32/rooms/R35Bj56rda7pkkYWH1MQ,
    metadata=SnapshotMetadata{
        hasPendingWrites=false,
        isFromCache=false
    },
    doc=Document{
        key=users/kCKkmgLmLGfvbPFK09qyZ5uoyw32/rooms/R35Bj56rda7pkkYWH1MQ,
        data=zza{
            (title=>Sample Room)
        };,
    version=SnapshotVersion(seconds=1523285961, nanos=350799000),
    hasLocalMutations=false
    }
}

显然,dateCreated 字段一开始就没有被检索到,这解释了 null 值。从我拥有的代码来看,我相信我正在正确处理解析。令人困惑的是我还有一个 Message 对象,它有一个 dateCreated 时间戳字段,我能够正确获取它。

P.S.:示例代码在 Kotlin 中,如果可以帮助使事情更清楚,我可以发布 Java 代码版本。


更新:这是 Firestore 消息文档的屏幕截图。

这是我的Message 模型类:

class Message(document: DocumentSnapshot) {

    companion object {
        private const val KEY_CONTENT = "content"
        private const val KEY_DATE_CREATED = "dateCreated"
    }

    private lateinit var mId: String
    private lateinit var mContent: String
    private lateinit var mDateCreated: Date

    // TODO: Figuring out why getDate doesn't seem to work for Rooms

    init {
        if (document.exists()) {
            mId = document.id
            mContent = document.getString(KEY_CONTENT)!!
            mDateCreated = document.getDate(KEY_DATE_CREATED)!!
        }
    }

    fun getId(): String = mId

    fun getContent(): String = mContent

    fun getDateCreated(): Date = mDateCreated

    fun getStringFormattedDateCreated() = FormatterUtil.getFormattedTimestamp(mDateCreated)

}

使Room 的日期可以为空 (?) 没有任何作用。

【问题讨论】:

  • JS客户端SDK有个firebase.firestore().settings({ timestampsInSnapshots: true });所以想知道会不会是这样。
  • 嘿@andyfusniak。我没有为 Firestore 使用任何额外的设置。 Message 的那个工作正常,但 Room 却不行。所以我认为不需要其他额外的设置。谢谢。

标签: android firebase google-cloud-firestore


【解决方案1】:

首先,您需要将POJO 项目上的名称与数据库中的名称保持一致,示例中的所有POJOs 都使用camelCase 注释编写,而在您的数据库中则不是。

如果你想让你的模型使用camelCase 而你的数据库没有,你可以使用注解PropertyName:

data class myFancyPojo(@PropertyName("name") val mName: String = "",
                   @ServerTimestamp
                   @PropertyName("timestamp")
                   val mTimestamp: Date? = null)

您错过了 POJO 构建器中参数上的注释 @ServerTimestamp,这标志着它是从服务器时间戳中夸大的。

用于标记要使用服务器时间戳填充的日期字段的注释。如果正在写入的 POJO 包含带有 @ServerTimestamp 注释的字段的 null,它将被替换为服务器生成的时间戳。

https://firebase.google.com/docs/reference/android/com/google/firebase/firestore/ServerTimestamp

最后,不要忘记,如果你用 Java 编写代码,你应该保留一个空的构造函数,如果你用 Kotlin 编写它,你应该给类的任何参数一个默认值。

【讨论】:

  • 嘿弗朗西斯科。 AFAIK,您提供的用例和示例适用于您打算保存到数据库的 POJO,此外,命名 POJO 以映射数据库上的内容的做法不是强制性的。我目前只是在读取数据。这个问题让我感到沮丧的是,它适用于我的一个模型类(Message),但不适用于Rooms。
【解决方案2】:

如果我正确理解了这个问题,那么您需要设置快照选项,或者您可能没有等待完整的结果。

我使用的是 Node.js 平台,因此您需要为您的 SDK 做同样的事情。

如果设置,则控制未设置的服务器时间戳的返回值 尚未设置为最终值。

通过指定“估计”,待处理的服务器时间戳返回估计值 基于本地时钟。这个估计将与最终的不同 值并导致这些值在服务器结果变为 可用。

通过指定“previous”,待处理的时间戳将被忽略并 而是返回它们之前的值。

如果省略或设置为'none',则默认返回null,直到 服务器值变为可用

这里是 Node.js 客户端 SDK 的链接。这可能会帮助您朝着正确的方向前进。 https://firebase.google.com/docs/reference/js/firebase.firestore.SnapshotOptions

【讨论】:

  • 嘿安迪。 Android 中似乎没有 SnapshotOptions 的对应物。我很肯定我正在等待完整的结果,因为 OnCompleteListener 只有在请求完成时才会触发。
  • @AL 真不幸。昨晚我在自己的 Node.js 项目中修复了一个错误,我没有等待 docRef.set 在读取结果之前得到空值。
【解决方案3】:

似乎没有正确解析日期的格式。

使用 firebase 我正在做的是将日期转换为 Unix 时间戳值,将该值存储在 firebase 中。 您可以使用 getTime() 方法来做到这一点。

当我检索数据时,同样,我将 Unix 时间戳值转换为 Date 类型。

Date date = new Date((long)timeStamp*1000);

例如:

数据 ------> Unix 时间戳

05/14/2018 @ 3:26pm (UTC) ------ > 1526311610

【讨论】:

  • 嗨,亚历克斯。我一开始就是这么想的。但就像我提到的,我有一个不同的对象,它也使用getDate() 来获取时间戳并且它工作正常。
  • 对不起,我现在明白了。在 Message 对象的代码中存储日期的操作是否完全相同?
猜你喜欢
  • 2021-06-05
  • 2020-02-14
  • 2019-06-07
  • 1970-01-01
  • 2018-09-04
  • 2020-02-08
  • 2018-07-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多