Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift Firestore:如何获取集合中的随机文档_Swift_Database_Firebase_Data Modeling_Google Cloud Firestore - Fatal编程技术网

Swift Firestore:如何获取集合中的随机文档

Swift Firestore:如何获取集合中的随机文档,swift,database,firebase,data-modeling,google-cloud-firestore,Swift,Database,Firebase,Data Modeling,Google Cloud Firestore,对于我的应用程序来说,能够从firebase中的一个集合中随机选择多个文档是至关重要的 因为Firebase(据我所知)没有内置的本机函数来实现这样的查询,所以我的第一个想法是使用查询游标来选择随机的开始和结束索引,前提是我拥有集合中的文档数 这种方法会起作用,但只能以有限的方式起作用,因为每次都会按顺序将每个文档与其相邻文档一起提供;然而,如果我能够通过父集合中的索引来选择文档,我可以实现随机文档查询,但问题是我找不到任何文档来描述如何实现这一点,或者即使您能够实现这一点 这是我想做的,考虑下

对于我的应用程序来说,能够从firebase中的一个集合中随机选择多个文档是至关重要的

因为Firebase(据我所知)没有内置的本机函数来实现这样的查询,所以我的第一个想法是使用查询游标来选择随机的开始和结束索引,前提是我拥有集合中的文档数

这种方法会起作用,但只能以有限的方式起作用,因为每次都会按顺序将每个文档与其相邻文档一起提供;然而,如果我能够通过父集合中的索引来选择文档,我可以实现随机文档查询,但问题是我找不到任何文档来描述如何实现这一点,或者即使您能够实现这一点

这是我想做的,考虑下面的FixStand模式:

root/
  posts/
     docA
     docB
     docC
     docD
然后在我的客户机(我在Swift环境中)中,我想编写一个查询来实现这一点:

db.collection("posts")[0, 1, 3] // would return: docA, docB, docD
有没有办法让我做点类似的事情?或者,是否有其他方法可以以类似的方式选择随机文档


请提供帮助。

使用随机生成的索引和简单查询,您可以从Cloud Firestore中的集合或集合组中随机选择文档

此答案分为4个部分,每个部分有不同的选项:

  • 如何生成随机索引
  • 如何查询随机索引
  • 选择多个随机文档
  • 为进行中的随机性重新播种
  • 如何生成随机索引 这个答案的基础是创建一个索引字段,当按升序或降序排列时,所有文档都会被随机排序。有不同的方法来创建它,所以让我们看看2,从最容易获得的开始

    自动识别版本 如果您使用的是我们的客户端库中提供的随机生成的自动ID,那么您可以使用相同的系统随机选择文档。在这种情况下,随机排序的索引是文档id

    在后面的查询部分中,您生成的随机值是一个新的自动id(,),您查询的字段是
    \uuuu name\uuuu
    字段,后面提到的“低值”是一个空字符串。这是迄今为止生成随机索引最简单的方法,无论使用何种语言和平台都可以使用

    默认情况下,文档名(
    \uuuuuu name\uuuuu
    )仅按升序编制索引,并且除了删除和重新创建之外,您也无法重命名现有文档。如果您需要这两种方法中的任何一种,您仍然可以使用此方法,只需将自动id存储为名为
    random
    的实际字段,而不是为此而重载文档名称

    随机整数版本 编写文档时,首先在有界范围内生成一个随机整数,并将其设置为名为
    random
    的字段。根据预期的文档数量,可以使用不同的有界范围来节省空间或降低碰撞风险(这会降低此技术的有效性)

    你应该考虑你需要哪些语言,因为会有不同的考虑。虽然Swift很简单,但JavaScript显然可以解决以下问题:

    • 32位整数:适用于小型(~10K)数据集
    • 64位整数:大型数据集(注意:JavaScript本机不支持,)
    这将创建一个索引,对文档进行随机排序。在后面的查询部分中,您生成的随机值将是这些值中的另一个,后面提到的“低值”将是-1

    如何查询随机索引 现在您有了一个随机索引,您将需要查询它。下面我们看一些简单的变体来选择1个随机文档,以及选择多个文档的选项

    对于所有这些选项,您都希望生成一个新的随机值,其形式与编写文档时创建的索引值相同,由下面的变量
    random
    表示。我们将使用此值在索引上查找一个随机点

    环绕 现在您有了一个随机值,可以查询单个文档:

    let postsRef = db.collection("posts")
    queryRef = postsRef.whereField("random", isGreaterThanOrEqualTo: random)
                       .order(by: "random")
                       .limit(to: 1)
    
    检查是否已返回文档。如果没有,请再次查询,但对随机索引使用“低值”。例如,如果使用随机整数,则
    低值
    0

    let postsRef = db.collection("posts")
    queryRef = postsRef.whereField("random", isGreaterThanOrEqualTo: lowValue)
                       .order(by: "random")
                       .limit(to: 1)
    
    只要您有一个文档,就可以保证至少返回一个文档

      getDocumentRandomlyParent(): Observable<any> {
        return this.getDocumentRandomlyChild()
          .pipe(
            expand((document: any) => document === null ? this.getDocumentRandomlyChild() : EMPTY),
          );
      }
    
      getDocumentRandomlyChild(): Observable<any> {
          const random = this.afs.createId();
          return this.afs
            .collection('my_collection', ref =>
              ref
                .where('random_identifier', '>', random)
                .limit(1))
            .valueChanges()
            .pipe(
              map((documentArray: any[]) => {
                if (documentArray && documentArray.length) {
                  return documentArray[0];
                } else {
                  return null;
                }
              }),
            );
      }
    
    private val firestore: FirebaseFirestore = FirebaseFirestore.getInstance()
    private var usersReference = firestore.collection("users")
    
    val rnds = (0..20001).random()
    
    usersReference.whereGreaterThanOrEqualTo("random",rnds).limit(1).get().addOnSuccessListener {
      if (it.size() > 0) {
              for (doc in it) {
                   Log.d("found", doc.toString())
               }
    } else {
        usersReference.whereLessThan("random", rnds).limit(1).get().addOnSuccessListener {
              for (doc in it) {
                      Log.d("found", doc.toString())
               }
            }
    }
    }
    
    双向的 环绕方法易于实现,允许您在只启用升序索引的情况下优化存储。一个不利因素是价值观可能受到不公平的保护。例如,如果10K中的前3个文档(A、B、C)的随机索引值为A:409496、B:436496、C:818992,则A和C被选中的几率仅为1/10K,而B被A的接近度有效屏蔽,并且只有大约1/160K的几率


    您可以在
    =
    之间进行随机选择,而不是在单个方向上进行查询并在未找到值时进行换行,我有一种方法可以在Firebase Firestore中随机获取列表文档,这非常简单。当我在Firestore上传数据时,我创建了一个字段名“position”,其随机值为1到1百万。当我从Fire store获取数据时,我将按字段“位置”设置顺序并更新其值,许多用户加载数据和数据始终会更新,并且将是随机值。

    对于使用Angular+Firestore的用户,基于@Dan McGrath技术,这里是代码片段

    下面的代码段返回1个文档

      getDocumentRandomlyParent(): Observable<any> {
        return this.getDocumentRandomlyChild()
          .pipe(
            expand((document: any) => document === null ? this.getDocumentRandomlyChild() : EMPTY),
          );
      }
    
      getDocumentRandomlyChild(): Observable<any> {
          const random = this.afs.createId();
          return this.afs
            .collection('my_collection', ref =>
              ref
                .where('random_identifier', '>', random)
                .limit(1))
            .valueChanges()
            .pipe(
              map((documentArray: any[]) => {
                if (documentArray && documentArray.length) {
                  return documentArray[0];
                } else {
                  return null;
                }
              }),
            );
      }
    
    private val firestore: FirebaseFirestore = FirebaseFirestore.getInstance()
    private var usersReference = firestore.collection("users")
    
    val rnds = (0..20001).random()
    
    usersReference.whereGreaterThanOrEqualTo("random",rnds).limit(1).get().addOnSuccessListener {
      if (it.size() > 0) {
              for (doc in it) {
                   Log.d("found", doc.toString())
               }
    } else {
        usersReference.whereLessThan("random", rnds).limit(1).get().addOnSuccessListener {
              for (doc in it) {
                      Log.d("found", doc.toString())
               }
            }
    }
    }
    

    发布此消息以帮助将来遇到此问题的任何人

    如果您使用的是自动ID,您可以生成一个新的自动ID并查询最接近的自动ID,如中所述

    我最近创建了一个随机报价api,需要从firestore集合中获取随机报价。
    这就是我解决公关问题的方法
    var db = admin.firestore();
    var quotes = db.collection("quotes");
    
    var key = quotes.doc().id;
    
    quotes.where(admin.firestore.FieldPath.documentId(), '>=', key).limit(1).get()
    .then(snapshot => {
        if(snapshot.size > 0) {
            snapshot.forEach(doc => {
                console.log(doc.id, '=>', doc.data());
            });
        }
        else {
            var quote = quotes.where(admin.firestore.FieldPath.documentId(), '<', key).limit(1).get()
            .then(snapshot => {
                snapshot.forEach(doc => {
                    console.log(doc.id, '=>', doc.data());
                });
            })
            .catch(err => {
                console.log('Error getting documents', err);
            });
        }
    })
    .catch(err => {
        console.log('Error getting documents', err);
    });
    
    .where(admin.firestore.FieldPath.documentId(), '>', key)
    
    import { Component, OnInit } from '@angular/core';
    import { Observable, merge, pipe } from 'rxjs';
    import { map, switchMap, filter, take } from 'rxjs/operators';
    import { AngularFirestore, QuerySnapshot } from '@angular/fire/firestore';
    
    @Component({
      selector: 'pp-random',
      templateUrl: './random.component.html',
      styleUrls: ['./random.component.scss']
    })
    export class RandomComponent implements OnInit {
    
      constructor(
        public afs: AngularFirestore,
      ) { }
    
      ngOnInit() {
      }
    
      public buttonClicked(): void {
        this.getRandom().pipe(take(1)).subscribe();
      }
    
      public getRandom(): Observable<any[]> {
        const randomNumber = this.getRandomNumber();
        const request$ = this.afs.collection('your-collection', ref => ref.where('random', '>=', randomNumber).orderBy('random').limit(1)).get();
        const retryRequest$ = this.afs.collection('your-collection', ref => ref.where('random', '<=', randomNumber).orderBy('random', 'desc').limit(1)).get();
    
        const docMap = pipe(
          map((docs: QuerySnapshot<any>) => {
            return docs.docs.map(e => {
              return {
                id: e.id,
                ...e.data()
              } as any;
            });
          })
        );
    
        const random$ = request$.pipe(docMap).pipe(filter(x => x !== undefined && x[0] !== undefined));
    
        const retry$ = request$.pipe(docMap).pipe(
          filter(x => x === undefined || x[0] === undefined),
          switchMap(() => retryRequest$),
          docMap
        );
    
        return merge(random$, retry$);
      }
    
      public getRandomNumber(): number {
        const min = Math.ceil(Number.MIN_VALUE);
        const max = Math.ceil(Number.MAX_VALUE);
        return Math.floor(Math.random() * (max - min + 1)) + min;
      }
    }
    
    
          new Promise<Timeline | undefined>(async (resolve, reject) => {
            try {
              let randomTimeline: Timeline | undefined;
              let maxCounter = 5;
              do {
                const randomId = this.afs.createId(); // AngularFirestore
                const direction = getRandomIntInclusive(1, 10) <= 5;
                // The firestore id is saved with your model as an "id" property.
                let list = await this.list(ref => ref
                  .where('id', direction ? '>=' : '<=', randomId)
                  .orderBy('id', direction ? 'asc' : 'desc')
                  .limit(10)
                ).pipe(take(1)).toPromise();
                // app specific filtering
                list = list.filter(x => notThisId !== x.id && x.mediaCounter > 5);
                if (list.length) {
                  randomTimeline = list[getRandomIntInclusive(0, list.length - 1)];
                }
              } while (!randomTimeline && maxCounter-- >= 0);
              resolve(randomTimeline);
            } catch (err) {
              reject(err);
            }
          })
    
    "field1" : "value1"
    "field2" : "value2"
    ...
    "random" : 13442 //this is the random number i generated upon creating document
    
    private val firestore: FirebaseFirestore = FirebaseFirestore.getInstance()
    private var usersReference = firestore.collection("users")
    
    val rnds = (0..20001).random()
    
    usersReference.whereGreaterThanOrEqualTo("random",rnds).limit(1).get().addOnSuccessListener {
      if (it.size() > 0) {
              for (doc in it) {
                   Log.d("found", doc.toString())
               }
    } else {
        usersReference.whereLessThan("random", rnds).limit(1).get().addOnSuccessListener {
              for (doc in it) {
                      Log.d("found", doc.toString())
               }
            }
    }
    }
    
     let totalDoc = db.collection("stat").get().then(snap=>snap.size)
    
     let  randomID = [ ]
    
     while(randomID.length < 20) {
         const randNo = Math.floor(Math.random() * totalDoc) + 1;
         if(randomID.indexOf(randNo) === -1) randomID.push(randNo);
     }
    
     const  randomDocs =  randomID.map(id => {
         db.collection("posts").doc(id).get()
             .then(doc =>  {
                  if (doc.exists) return doc.data()
              })
             .catch(error => {
                  console.log("Error getting document:", error);
             });
       })
    
    FirebaseFirestore db;
    
        void Start()
        {
            db = FirebaseFirestore.DefaultInstance;
        }
    
        public void GetRandomDocument()
        {
    
           Query query1 = db.Collection("Sports").WhereGreaterThanOrEqualTo(FieldPath.DocumentId, db.Collection("Sports").Document().Id).Limit(1);
           Query query2 = db.Collection("Sports").WhereLessThan(FieldPath.DocumentId, db.Collection("Sports").Document().Id).Limit(1);
    
            query1.GetSnapshotAsync().ContinueWithOnMainThread((querySnapshotTask1) =>
            {
    
                 if(querySnapshotTask1.Result.Count > 0)
                 {
                     foreach (DocumentSnapshot documentSnapshot in querySnapshotTask1.Result.Documents)
                     {
                         Debug.Log("Random ID: "+documentSnapshot.Id);
                     }
                 } else
                 {
                    query2.GetSnapshotAsync().ContinueWithOnMainThread((querySnapshotTask2) =>
                    {
    
                        foreach (DocumentSnapshot documentSnapshot in querySnapshotTask2.Result.Documents)
                        {
                            Debug.Log("Random ID: " + documentSnapshot.Id);
                        }
    
                    });
                 }
            });
        }
    
    queryRef = postsRef.whereField("random", isGreaterThanOrEqualTo: lowValue).where("__name__", isNotEqualTo:"PreviiousId")
                   .order(by: "random")
                   .limit(to: 1)