简体   繁体   English

如何在Firebase的iOS SDK上执行分页查询?

[英]How do I perform a pagination query on Firebase's iOS SDK?

Firebase模型

This is my model. 这是我的模特。

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

My code works -- it gets the last 5 messages (8-12). 我的代码有效 - 它获取最后5条消息(8-12)。

However, what if I have a function query the next 5 messages (2-6)? 但是,如果我有一个函数查询接下来的5条消息(2-6)怎么办? With a start and offset. 有一个开始和偏移。 How can I query this? 我怎么查询这个?

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

This is kind of a shot in the dark but it seems like it should work based on documentation here https://www.firebase.com/docs/ios-api/Classes/Firebase.html#//api/name/queryStartingAtValue : 这是一个在黑暗中的镜头,但它似乎应该基于这里的文档https://www.firebase.com/docs/ios-api/Classes/Firebase.html#//api/name/queryStartingAtValue

On spending too much time I have figured it out and here is the solution. 花了太多时间我已经弄明白了,这就是解决方案。 This is Objective-C code you can convert it into swift. 这是Objective-C代码,您可以将其转换为swift。 Call below function for paging purpose. 调用以下功能以进行寻呼。

- (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);
            }
        }];
    }
}

And here is description of objects you needed: 这里是您需要的对象的描述:

#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

Good Luck!! 祝好运!! (y) (y)的

在此输入图像描述

Swift 3.x 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)
    })
}

Here the 'parseMessage' function is my custom function to convert snapshot into message model, you can use your own. 这里的'parseMessage'函数是我的自定义函数,用于将快照转换为消息模型,您可以使用自己的。 the message key is the key of earliest message you loaded in initial firebase call. 消息密钥是您在初始firebase调用中加载的最早消息的密钥。

Swift 2017 斯威夫特2017

I'd like to present an as elegant solution as i could made for this task of pagination with the firebase. 我想提出一个优雅的解决方案,就像我为火焰基地的这个任务所做的那样。 This method called both when initializing and loading more data: 此方法在初始化和加载更多数据时都会调用:

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

The function for reloading data in controller. 在控制器中重新加载数据的功能。

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

This is called when a user reach the end of tableView. 当用户到达tableView的末尾时调用此方法。

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

Making array from snapshot 从快照制作数组

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

Thanks this video for clarifying some moments with "cool" firebase reference api. 感谢这个视频 ,用“酷”的火山参考API来澄清一些时刻。
Good luck in development and ask any questions if found something unclear. 发展好运 ,如果发现不清楚的话,可以提出任何问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM