【问题标题】:How do I perform a pagination query on Firebase's iOS SDK?如何在 Firebase iOS SDK 中执行分页查询?
【发布时间】:2015-06-16 15:34:38
【问题描述】:

这是我的模型。

messagesRef = Firebase(url: "https://"+CONSTANTS.FirebaseDB+".firebaseio.com/messages/1:1000")
    messagesRef.queryLimitedToLast(5).observeEventType(FEventType.ChildAdded, withBlock: { (snapshot) in
        self.message_list.append(snapshot) // it works.
    });
});

我的代码有效 - 它获取最后 5 条消息 (8-12)。

但是,如果我有一个函数查询接下来的 5 条消息 (2-6),该怎么办?有一个开始和偏移。我该如何查询这个?

【问题讨论】:

标签: ios swift firebase


【解决方案1】:
messagesRef = Firebase(url: "https://"+CONSTANTS.FirebaseDB+".firebaseio.com/messages/1:1000")messagesRef
.queryOrderedByKey()
.queryStartingAtValue(5)
.queryEndingAtValue(10)
.observeEventType(FEventType.ChildAdded, withBlock: { (snapshot) in self.message_list.append(snapshot) });

这有点像在黑暗中拍摄,但它似乎应该根据这里的文档工作https://www.firebase.com/docs/ios-api/Classes/Firebase.html#//api/name/queryStartingAtValue

【讨论】:

  • 这行得通,因为他的键是数字。否则你会怎么做?
  • 降序怎么做?
  • @nodebase 检查我的答案。这会有所帮助。
  • @TheTiger,一旦添加到模型中的数组中,您就可以反转。艾。 array.insert[DL 数据],位于:array.count)
【解决方案2】:

关于花费太多时间,我已经想通了,这就是解决方案。这是 Objective-C 代码,您可以将其转换为 swift。 调用下面的函数进行分页。

- (void)loadMoreMessages {
    
    if (!lastMessageKey) {
        // Loading messages first time
        [[[msgsReference queryOrderedByKey] queryLimitedToLast:K_MESSAGES_PER_PAGE] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
            if (snapshot.exists) {
                
                for (FIRDataSnapshot *child in snapshot.children) {
                   
                    NSMutableDictionary *dict = [child.value mutableCopy];
                    [dict setObject:child.key forKey:@"id"];
                    [messages addObject:dict];
                }
                
                lastMessageKey = [[snapshot.children.allObjects firstObject] key];
                NSLog(@"%@", messages);
            }
        }];
    }
    else {
        // Paging started
        [[[[msgsReference queryOrderedByKey] queryLimitedToLast:K_MESSAGES_PER_PAGE + 1] queryEndingAtValue:lastMessageKey] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
           
            if (snapshot.exists) {
       
                NSInteger count = 0;
                NSMutableArray *newPage = [NSMutableArray new];
                for (FIRDataSnapshot *child in snapshot.children) {
                    
                    // Ignore last object because this is duplicate of last page
                    if (count == snapshot.childrenCount - 1) {
                        break;
                    }
                    
                    count += 1;
                    NSMutableDictionary *dict = [child.value mutableCopy];
                    [dict setObject:child.key forKey:@"id"];
                    [newPage addObject:dict];
                }
                
                lastMessageKey = [[snapshot.children.allObjects firstObject] key];

                // Insert new messages at top of old array
                NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange: NSMakeRange(0, [newPage count])];
                [messages insertObjects:newPage atIndexes:indexes];
                NSLog(@"%@", messages);
            }
        }];
    }
}

这里是您需要的对象的描述:

#define K_MESSAGES_PER_PAGE 50 // A macro defining the numbers in one request
msgsReference // Firebase database messages node reference I'm also attaching the screenshot of my db structure for make you more clear
lastMessageKey // Is a NSString object which store the first key of last page
messages // Is a NSMutableArray storing the result

祝你好运!! (y)

【讨论】:

  • 很好的答案。这应该被接受为答案。
  • 什么是lastMessageKey?如何将最后一页的第一个键存储在lastMessageKey中?
  • @HimaliShah 这是一个NSString 对象,代码中已经提到了我们需要为其分配什么值。检查这一行lastMessageKey = [[snapshot.children.allObjects firstObject] key];
  • 你会如何为所有“朋友”的“提要”执行此操作?目前我正在收集所有朋友的 ID,然后在firebase.child(id).child(userposts) 上提出请求,但我不知道如何在这里进行分页
  • @DavidSeek - 考虑chat_xyz 是你的friendsmessagesuserposts
【解决方案3】:

Swift 3.x

func fetchEarlierMessages(chatGroupId: String, messageKey: String, completion: @escaping ([Message]?) -> ()) {
    previousMessageRef = root.child("messages").child(chatGroupId)
    messageValueHandle = previousMessageRef.queryOrderedByKey().queryLimited(toLast: 10).queryEnding(atValue: messageKey).observe(.value, with: { snapshot in
        var messages: [Message] = []
        for child in snapshot.children.allObjects as! [FIRDataSnapshot] {
            guard var item = child.value as? [String: AnyObject] else { return }
            item["message_id"] = child.key as AnyObject
            if let message = self.parseMessage(snapshot: child) {
                messages.append(message)
            }
        }
        messages.removeLast()
        completion(messages)
    })
}

这里的'parseMessage'函数是我自定义的将快照转换为消息模型的函数,你可以使用你自己的。消息键是您在初始 firebase 调用中加载的最早消息的键。

【讨论】:

    【解决方案4】:

    斯威夫特 2017

    我想提出一个尽可能优雅的解决方案来完成这个使用 firebase 进行分页的任务。此方法在初始化和加载更多数据时都调用:

    var items: [ItemEntity] = []
    var theEndOfResults = false
    var lastLoadedItem: ItemEntity? {
        return items.last
    }
        
    func loadItems() {
        let isLoadingMore = lastLoadedItem != nil
            
        Decorator.showStatusBarLoader()
        self.databaseReference
            .child("items")
            .queryOrdered(byChild: "date")
            .queryEnding(atValue: isLoadingMore ? lastLoadedItem!.date.stringValue : Date.distantFuture.stringValue)
            .queryLimited(toLast: 5)
            .observeSingleEvent(of: .value) { snapshot in
                var items = self.array(from: snapshot)
                    .map { ItemEntity(parentKey: $0.parentKey, dictionary: $0.dict) }
    
                    self.theEndOfResults = (self.lastLoadedItem == items.last) // prevent loading when it's no more items
                    if isLoadingMore { items.removeFirst() } // removing as the firebase sending a repeated one
                    self.items.append(contentsOf: items)
    
                    self.reloadData()
            }
        }
    

    在控制器中重新加载数据的功能。

    override func reloadData() {
        tableV.reloadData()
        refreshControl.endRefreshing()
        tableV.loadControl?.endLoading()
        Decorator.hideStatusBarLoader()
    }
    

    当用户到达 tableView 的末尾时调用它。

    @objc public func loadMore() {
        guard self.theEndOfResults == false else { tableV.loadControl?.endLoading(); return }
        self..loadItems()
    }
    

    从快照制作数组

    func array(from snapshot: DataSnapshot) -> [ParseResult] {
        var items = [ParseResult]()
        if let snapshots = snapshot.children.allObjects as? [DataSnapshot] {
            for snap in snapshots {
                if let postDictionary = snap.value as? Dictionary<String, AnyObject> {
                    items.append((snap.key, postDictionary))
                }
            }
        }
        print("? DATA COME:\r\(snapshot)")
        //or u can use: dump(items, indent: 2, maxDepth: 5, maxItems: 15)
        return items.reversed()
    }
    

    感谢 video 用“酷”的 firebase 参考 api 澄清一些时刻。
    Good luck 正在开发中,如果发现不清楚的地方,请提出任何问题。

    【讨论】:

    • 这不是分页功能 - 因为重新加载表格视图时它可能会再次加载表格视图中的 100 个元素 - 您只需要加载新的元素
    猜你喜欢
    • 1970-01-01
    • 2018-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-15
    • 2017-04-29
    • 1970-01-01
    相关资源
    最近更新 更多