【问题标题】:How to get unique random product in node Firebase?如何在节点 Firebase 中获得唯一的随机产品?
【发布时间】:2018-05-18 14:05:34
【问题描述】:

数据:

- products
   - -L74Pc7oVY22UsCETFBv
       - name: "gjwj"
       - category: "hreggrrg"
       - location: "vjhiwehifwe"
       - price: 44
       - color: fassaf
   - -L74uJ7oVYcVNyCteFBz
       - name: "uygfwh"
       - category: "hhhjwwwom"
       - location: "pervrr"
       - price: 33
       - color: yrtrr
   ......................

我在节点 products 中有很多产品,超过 1000 种产品。我可以在ListView 中显示所有内容。我只想向用户显示一个唯一的随机数,例如亮点,但不是全部下载,只有一个。

代码:

ValueEventListener v = new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        for(DataSnapshot child : dataSnapshot.getChildren()) {
            String name = (String) child.child("name").getValue().toString();
            Toast.makeText(MainActivity.this, name, Toast.LENGTH_SHORT).show();
            //How to get?????
        }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
};
FirebaseDatabase.getInstance().getReference().addListenerForSingleValueEvent(v);

如何在节点 Firebase 中获取唯一的随机产品?

【问题讨论】:

    标签: java android firebase firebase-realtime-database


    【解决方案1】:

    好吧,这里有一些关于 SOF 的好答案,但都是分开的,所以我会尝试用两种方法回答你的问题。

    但首先,在编写一些代码之前,我可以告诉你这段代码不起作用,因为你在参考中缺少一个孩子,即products,显然假设products 节点是直接的Firebase 数据库根目录的子节点。

    实际答案:

    假设您的数据库结构如下所示(其中products 节点是您的 Firebase 数据库的直接子节点):

    Firebase-root
       |
       --- products
             |
             --- productIdOne
             |      |
             |      --- name: "gjwj"
             |      |
             |      --- category: "hreggrrg"
             |      |
             |      --- location: "vjhiwehifwe"
             |      |
             |      --- price: 44
             |      |
             |      --- color: "fassaf"
             |
             --- productIdTwo
             |      |
             |      --- name: "uygfwh"
             |      |
             |      --- category: "hhhjwwwom"
             |      |
             |      --- location: "pervrr"
             |      |
             |      --- price: 33
             |      |
             |      --- color: "yrtrr"
             |
             --- //And so on
    

    要获得随机产品,请使用以下代码:

    ListView listView = (ListView) findViewById(R.id.list_view);
    ArrayAdapter arrayAdapter = new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, randomProductList);
    listView.setAdapter(arrayAdapter);
    DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
    DatabaseReference productsRef = rootRef.child("products"); //Added call to .child("products")
    ValueEventListener valueEventListener = new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            List<String> productList = new ArrayList<>();
            for(DataSnapshot ds : dataSnapshot.getChildren()) {
                String name = ds.child("name").getValue(String.class);
                productList.add(name);
            }
    
            int productListSize = productList.size();
            List<String> randomProductList = new ArrayList<>();
    
            randomProductList.add(new Random().nextInt(productListSize)); //Add the random product to list
            arrayAdapter.notifyDatasetChanged();
        }
    
        @Override
        public void onCancelled(DatabaseError databaseError) {
            Log.d(TAG, "Error: ", task.getException()); //Don't ignore errors!
        }
    };
    productsRef.addListenerForSingleValueEvent(valueEventListener);
    

    为了获取所有产品,您需要遍历products 节点的所有子节点。所以必须拨打child("products")

    如果您想要多个随机产品,那么您可以创建一个循环并在 randomProductList 中添加任意数量的随机产品。

    这被称为经典解决方案,您可以将其用于仅包含少量记录的节点,但如果您害怕获取大量数据,那么我会向您推荐第二种方法。这还涉及通过添加一个名为productIds 的新节点对您的数据库进行一些更改。您的数据库结构应如下所示:

    Firebase-root
       |
       --- products
       |     |
       |     --- productIdOne
       |     |      |
       |     |      --- //details
       |     |
       |     --- productIdTwo
       |            |
       |            --- //details
       |      
       --- productIds
              |
              --- productIdOne: true
              |
              --- productIdTwo: true
              |
              --- //And so on
    

    因此,正如您在问题中提到的,如果您想避免下载包含具有所有属性的所有产品的整个 products 节点,则必须创建一个名为 productIds 的单独节点。因此,要获得单个产品,您只需下载一个仅包含产品 ID 的简单节点。

    这种做法称为非规范化(复制数据),是 Firebase 的常见做法。为了更好地理解,我建议您观看此视频,Denormalization is normal with the Firebase Database

    但是请记住,您在这个新创建的节点中添加随机产品的方式与不再需要时需要删除它们的方式相同。

    所以要获得随机产品,您需要查询数据库两次。请看下面的代码:

    DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
    DatabaseReference productIdsRef = rootRef.child("productIds");
    ValueEventListener valueEventListener = new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            List<String> productIdsList = new ArrayList<>();
            for(DataSnapshot ds : dataSnapshot.getChildren()) {
                String productId = ds.getKey();
                productIdsList.add(productId);
            }
    
            int productListSize = productList.size();
            List<String> randomProductList = new ArrayList<>(););
    
            DatabaseReference productIdRef = rootRef.child("products").child(productIdsList.get(new Random().nextInt(int productListSize));
            ValueEventListener eventListener = new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    String name = dataSnapshot.child("name").getValue(String.class);
                    Log.d("TAG", name);
                }
    
                @Override
                public void onCancelled(DatabaseError databaseError) {
                    Log.d(TAG, "Error: ", task.getException()); //Don't ignore errors!
                }
            };
            productIdRef.addListenerForSingleValueEvent(eventListener);
        }
    
        @Override
        public void onCancelled(DatabaseError databaseError) {
            Log.d(TAG, "Error: ", task.getException()); //Don't ignore errors!
        }
    };
    productIdsRef.addListenerForSingleValueEvent(valueEventListener);
    

    当您对 Firebase 数据库执行查询时,可能会有多个结果。所以dataSnapshot 包含这些结果的列表。即使只有一个结果,dataSnapshot 对象也会包含一个结果列表。

    【讨论】:

    • DatabaseReference productIdRef = rootRef.child("products").child(productIdsList.get(new Random().nextInt(int productListSize)) 它在以下行中显示错误 int productListSize 已在范围内定义.
    • 我们可以在这里使用 Pager 概念吗?
    • @RaviMalik 没有看到你的代码,我帮不上什么忙。如果您在实施时遇到困难,请使用自己的 MCVE 发布一个新问题,向我们展示您的尝试,以便我和其他 Firebase 开发人员可以帮助您。
    • 从代码中我大部分都清楚了,但你能解释一下这行 DatabaseReference productIdRef = rootRef.child("products").child(productIdsList.get(new Random( ).nextInt(int productListSize))
    • @RaviMalik 在这行代码中,我们使用列表中的随机索引创建引用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-03
    • 2022-12-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多