您如何设置多个查询来限制发送到设备的用户数量,而不是 运行 所有用户的快照?

Instead of running a snapshot for all users, how do you set up multiple queries to limit the number of users sent to the device?

我所拥有的:所有用户的快照,带有一堆 if 语句,最终 returns 显示了一组用户。

我需要:要在快照前一行的 .query 中使用的最终用户数组。

为什么我需要这个:这一行是为了让整个用户数据库不在客户端上 运行。

更具体地说,我需要查询什么:A) 具有 child“标题”(timestamp) 且时间戳为今天的用户, AND, B) 距离当前用户 3000 英里。

JSON 数据库

    "people" : {
"02PdiNpmW3MMyJt3qPuRyTpHLaw2" : {
  "Coordinates" : {
    "latitude" : -25.809620667034363,
    "longitude" : 28.321706241781342
  },
  "PhotoPosts" : "https://firebasestorage.googleapis.com/v0/b/daylike-2f938.appspot.com/o/images%2F02PdiNpmW3MMyJt3qPuRyTpHLaw2%2FPhotoPosts?alt=media&token=24fee778-bcda-44e3-aa26-d7c2f8509740",
  "caption" : 1602596281762, /// this is timestamp
  "postID" : "02PdiNpmW3MMyJt3qPuRyTpHLaw2"
},
  "e1" : “cvvvv666",
  "e2" : "aol.com",
  "      "postID" : "0RnqWV7Gd9Z0bUW9nUvizMQOjK73",
  "users" : "cvvvv666@aol.com"
},
    

.

var dict = CLLocation()
         ...
dict = CLLocation(latitude: lat, longitude: lon)
        ...
let thisUsersUid = Auth.auth().currentUser?.uid
    //this line below is where the refArtists2 query should go. in other words send all users to device that meet the 2 if statements, which is represented by self.people.append(peopl)//
    let refArtists2 = Database.database().reference().child("people").queryOrdered(byChild: "caption").queryEqual(toValue: ANY Timestamp in today).queryOrdered(byChild:Coordinates). queryEqual(toValue:ThoseCoordinates which make the distance to current user less than 3000 miles)     
    refArtists2.observe(DataEventType.value,  with: {  snapshot in
        if snapshot.childrenCount>0{
            self.people.removeAll()
            for people in snapshot.children.allObjects as! [DataSnapshot] {
         if people.key != thisUsersUid {
                let peopleObject = people.value as? [String: AnyObject]
                let peopleCoordinates = peopleObject?["Coordinates"] as? String
                let peoplecaption = peopleObject?["caption"] as? Int //is timestamp
                let peoplepostID = peopleObject?["postID"] as? String
                let coordSnap = people.childSnapshot(forPath: "Coordinates")
                guard let lat = coordSnap.childSnapshot(forPath: "latitude").value as? CLLocationDegrees else { return  }
                guard let lon = coordSnap.childSnapshot(forPath: "longitude").value as? CLLocationDegrees else { return  }
                let locCoord = CLLocation(latitude: lat, longitude: lon)
                let coordSnap12 = people.childSnapshot(forPath: "caption").value as? Int ?? 0
                let date = Date(timeIntervalSince1970: TimeInterval(coordSnap12)/1000.0)
                //let secondsInDay = 86400
                **if Calendar.current.isDateInToday(date)** {
                    let distance = locCoord.distance(from: self.dict)
                    print(distance, "distancexy")
                    **if distance/1609.344 < 3000**{
                        let peopl = Userx(Coordinates: peopleCoordinates, distance:distance, caption: peoplecaption, postID: peoplepostID)
                        self.people.append(peopl)
                        let d = people.key as! String
                        self.printPersonInfo(uid:d)   ///////This is used to reload the data
                    } else {
                        print ("w")
                    }
                } else {
                    print ("alphaaa") 
                }   
            }
            print("aaaaaaaa", self.people.map {[=12=].distance})    
        } 
        self.people.sort { ([=12=].distance ?? 0) < (.distance ?? 0) }     ////////This sorting with distance is used with returning the cell. people is used as uid array to return the cell.   
    }      
})
} else {
    print("no")
}
})
                            

附带说明:self.people.sort { ([=14=].distance ?? 0) < (.distance ?? 0) }排序很重要,因此查询不应妨碍排序。我有点担心使用 queryOrdered,因为它以错误的顺序对用户数组进行排序。如果是,则 C) 查询应该是:用户的顺序必须是最接近登录用户的用户在前。离登录用户最远的必须在数组中排在最后。

另一种提问方式是:不是运行创建所有用户的快照,而是在制作快照时如何查询快照的'end result sort'?

时间戳是自 1970 年以来的秒数

我对下面日期查询的尝试。我拿了代码并尝试将获取日期的代码放在实际查询之前(目前获取日期的代码在快照之后所有用户)。

    var ppp: String!  ////this should be the uid of all users in db

    let people = Database.database().reference().child("people").child(self.ppp).child("captions")
people.observe(DataEventType.value, with: {  snapshot in
    let captionss = snapshot.value as? Int ?? 0
    let date = Date(timeIntervalSince1970: TimeInterval(captionss)/1000.0)       
    let query1 = Database.database().reference().child("people").queryOrdered(byChild: "caption").where?(isDateInToday(date))

编辑:这个答案在 Firestore 中,而不是实时数据库中。但是,概念是一样的。

该题为多题合一;询问距离、复合查询以及一般如何查询 Firebase。我将 post 这个答案来解决后两个问题,距离查询在问题的评论中解决。

一旦理解了查询模式,它们就会变得更容易,最重要的是;更明显的是,你的数据结构取决于你想运行针对该数据进行的查询。

假设我们有一个包含用户文档的用户集合 - 每个 documentId 都是用户 uid

users
   uid_0
      name: "Leroy"

然后我们有用户的 posts - 每个 post 包含一些文本,post 的时间戳,[=46= 的用户的 uid ]编辑它,主题是什么,url 出现在 post 中的图片。请注意,我将 posts 存储在一个单独的集合中;当我们只想了解他们的 post.

时,为什么要读取一堆用户数据
posts
   post_id
      postText: "pretty flowers"
      postDate: "20201103"
      postUrl: "www....."
      postUid: "uid_0"
      postTopic: "flowers"

假设我们想要从今天开始获取有关鲜花的 posts,然后还获取 posters 的姓名并输出谁 post 发了消息以及他们发了什么说。

为此,我们需要一个复合查询,然后是一个子查询来检索 post 用户姓名。

func getTodaysPostsAboutFlowers() {
    let postsCollection = self.db.collection("posts")
    let query = postsCollection.whereField("postDate", isEqualTo: "20201103").whereField("postTopic", isEqualTo: "flowers")
    query.getDocuments(completion: { snapshot, error in
        if let err = error {
             print(err.localizedDescription)
             return
         }

         guard let docs = snapshot?.documents else { return }

         for doc in docs {
            let postText = doc.get("postText") as? String ?? "No text"
            guard let postersUid = doc.get("postUid") as? String else { return }
            self.outputPostTextAndUserName(withText: postText, andUid: postersUid)
         }
    })
}

以上代码对 post 日期字段和 post 主题字段执行复合查询。

上面然后调用另一个函数来检索用户名并输出名称和他们所说的内容

func outputPostTextAndUserName(withText: String, andUid: String) {
    let usersCollection = self.db.collection("users")
    let theUserDoc = usersCollection.document(andUid)
    theUserDoc.getDocument(completion: { documentSnapshot, error in
        if let err = error {
             print(err.localizedDescription)
             return
         }

        if let doc = documentSnapshot {
            let postersName = doc.get("name") as? String ?? "No Name"
            print("\(postersName) posted: \(withText)")
        }
    })
}

和输出

Leroy posted: pretty flowers

如您所见,无需加载所有用户,无需迭代结果等。即使您有十亿用户,这也只会 return 该数据的一个子集是处理庞大数据集时的最佳实践;只获取您感兴趣的数据。

编辑。 OP 正在询问查询包含今天的节点。简单的解决方案是让一个子节点包含一个包含特定日期数据的时间戳,然后另一个子节点仅包含 YYYYMMDD 格式的今天数据。

人 uid_x 时间戳:9023490823498 //日期(timeIntervalSince1970: todaystamp: "20201106" // yyyymmdd 格式

这使得查询包含今天的节点变得非常简单。