【问题标题】:How can I query data with different firebase database names?如何使用不同的 firebase 数据库名称查询数据?
【发布时间】:2019-04-16 14:10:37
【问题描述】:

这是我作为示例给出的 Firebase 数据库示例。这里我想做“+90 505 696 1234”值的电话号码和文本的值一起用recycler视图查询和排序值。我只是设法做到了。但不是我想要的方式。此电话号码将有两个或多个值。你可以在数据库中看到这个。

“+90 505 696 1234”:“A”和“+90 505 696 1234”:“AA”。当我质疑这个数字时,我想看到这个数据。但是我无法创建 CategoryItem 类,因为我的数据库名称是可变的。我不知道该怎么做。不会有固定的数据库名称。用户会查询不同的号码。如何为此创建 CategoryItem 类?

我的 Firebase 数据库

{
  "ContactPhoneNumbers" : {
    "-LcaHYcsoGA-VT8yvgGf" : {
      "+90 505 696 1234" : "A",
      "+90 506 854 2345" : "B",
      "+90 530 408 3456" : "C",
      "+90 535 966 4567" : "D",
      "+90 536 782 5678" : "E",
      "+90 546 934 67 89" : "F",
      "+905304080001" : "G",
      "+905316910002" : "H",
      "+905359660003" : "I",
      "+905367820004" : "J",
      "+905425420005" : "K",
      "+905469340006" : "L",
      "05056960007" : "M"
    },
    "-LcaH_gtgarJwbY5-C08" : {
      "+90 505 696 1234" : "AA",
      "+90 506 854 2345" : "BB",
      "+90 530 408 3456" : "CAC",
      "+90 535 966 4567" : "AAA",
      "+90 536 782 5678" : "CAB",
      "+90 546 934 67 89" : "BB",
      "+905304080001" : "A",
      "+905316910002" : "BBB",
      "+905359660003" : "DDD",
      "+905367820004" : "EEE",
      "+905425420005" : "FFF",
      "+905469340006" : "L",
      "05056960007" : "M"
    }
  }
}

我的活动

public class MainActivity extends AppCompatActivity {

    EditText Search_Edit_Text;
    Button Search_Button;
    RecyclerView Search_Contact_List;

    DatabaseReference mUserDatabase;

    FirebaseRecyclerOptions<CategoryItem> options,options2;
    FirebaseRecyclerAdapter<CategoryItem,CategoryViewHolder> adapter;

    Query firebaseSearchQuery,asd;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        mUserDatabase = FirebaseDatabase.getInstance().getReference().child("ContactPhoneNumbers");

      
        Search_Edit_Text = (EditText) findViewById(R.id.Search_Edit_Text);
        Search_Button = (Button) findViewById(R.id.Search_Button);

        Search_Contact_List = (RecyclerView) findViewById(R.id.Search_Contact_List);
        Search_Contact_List.setHasFixedSize(true);
        GridLayoutManager gridLayoutManager = new GridLayoutManager(getBaseContext(),2);
        Search_Contact_List.setLayoutManager(gridLayoutManager);




        Search_Button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                String searchText = Search_Edit_Text.getText().toString().trim();

                firebaseUserSearch(searchText);
            }
        });

 }

    private void firebaseUserSearch(final String searchText) {


        firebaseSearchQuery = mUserDatabase.orderByChild(searchText).startAt("").endAt("" + "\uf8ff");

        options2 = new FirebaseRecyclerOptions.Builder<CategoryItem>()
                .setQuery(firebaseSearchQuery,CategoryItem.class)
                .build();

        adapter = new FirebaseRecyclerAdapter<CategoryItem, CategoryViewHolder>(options2) {
            @Override
            protected void onBindViewHolder(@NonNull final CategoryViewHolder holder, int position, @NonNull final CategoryItem model) {

                Toast.makeText(MainActivity.this, model.getName(), Toast.LENGTH_SHORT).show();
            }


            @NonNull
            @Override
            public CategoryViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

                View itemView = LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.list_layout,parent,false);
                return new CategoryViewHolder(itemView);

            }
        };

        setCategory();
    }

    private void setCategory() {

        adapter.startListening();
        Search_Contact_List.setAdapter(adapter);
    }
}

我的分类项目

这段代码完全是一个例子。当我将名称“字符串”写为字符串时,我需要在电话号码中创建一个名称。我不想要这个。我想查看对应电话号码的值。

public class CategoryItem {

    public String name ;

    public CategoryItem() {

    }

    public CategoryItem(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

【问题讨论】:

  • 我的数据库名称是可变的 为什么?您是否在每个数据库中随机排列数据?
  • 数据库名称是随机的。但我想查询数据库名称。例如,当我查询“155”时,我希望它给出“警察”。我想为此创建一个类。 @B001ᛦ
  • 数据库名称将是随机的... 对我来说没有意义。听起来像一个 XY 问题
  • @B001ᛦ 他们的意思是每个数据库条目的键是不固定的(电话号码)。他们正在努力将下载的数据转换为可以使用的结构化 Java 类。

标签: java android firebase firebase-realtime-database


【解决方案1】:

你不能那样做。不知道它的名字就不可能得到一个特定的密钥。您是否使用键来索引数据?如果是这样,也许不要这样做,只需在节点中存储一个索引,以便您可以设置最终标题。

【讨论】:

    【解决方案2】:

    因为您使用的是动态键,所以没有有效的方法可以使用orderByChild() 来获得您想要的结果,而无需将整个“ContactPhoneNumbers”节点下载到客户端设备然后执行排序和过滤。另一种方法是保留联系人的索引。

    orderByChild()

    这仅对小型数据集有用。当“ContactPhoneNumbers”变大时,不要依赖它,因为它会增加您的成本。每次调用时,您的联系人数据库都会被完整下载。

    String phoneSearchText = "+90 530 408 3456";
    Query q = mUserDatabase.orderByChild(phoneSearchText).startAt("");
    

    索引

    当您的数据依赖于动态键时,您已经实现了自定义索引实现,而不是使用 RTDB 的内置索引系统(请参阅indexing data)。

    您可以在客户端(更便宜)或服务器端(更易于维护)构建和维护索引。

    为了安全性和可维护性,我将包含一些修改后的代码,用于基于Cloud Functions for Firebase 构建的服务器端实现。

    此代码将生成以下索引,可以查询电话号码并包含所有不同的变体。对“ContactPhoneNumbers”树所做的任何更改都将自动镜像到该索引。您应该 secure this index 避免被客户端设备更改。

    {
      "ContactPhoneNumbersIndex": {
        "+90 505 696 1234": {
          "-LcaHYcsoGA-VT8yvgGf": "A",
          "-LcaH_gtgarJwbY5-C08": "AA"
        },
        "+90 506 854 2345": {
          "-LcaHYcsoGA-VT8yvgGf": "B",
          "-LcaH_gtgarJwbY5-C08": "BB"
        },
        "+90 530 408 3456": {
          "-LcaHYcsoGA-VT8yvgGf": "C",
          "-LcaH_gtgarJwbY5-C08": "CAC"
        },
        "+90 535 966 4567": {
          "-LcaHYcsoGA-VT8yvgGf": "D",
          "-LcaH_gtgarJwbY5-C08": "AAA"
        },
        "+90 536 782 5678": {
          "-LcaHYcsoGA-VT8yvgGf": "E",
          "-LcaH_gtgarJwbY5-C08": "CAB"
        },
        "+90 546 934 67 89": {
          "-LcaHYcsoGA-VT8yvgGf": "F",
          "-LcaH_gtgarJwbY5-C08": "BB"
        },
        "+905304080001": {
          "-LcaHYcsoGA-VT8yvgGf": "G",
          "-LcaH_gtgarJwbY5-C08": "A"
        },
        "+905316910002": {
          "-LcaHYcsoGA-VT8yvgGf": "H",
          "-LcaH_gtgarJwbY5-C08": "BBB"
        },
        "+905359660003": {
          "-LcaHYcsoGA-VT8yvgGf": "I",
          "-LcaH_gtgarJwbY5-C08": "DDD"
        },
        "+905367820004": {
          "-LcaHYcsoGA-VT8yvgGf": "J",
          "-LcaH_gtgarJwbY5-C08": "EEE"
        },
        "+905425420005": {
          "-LcaHYcsoGA-VT8yvgGf": "K",
          "-LcaH_gtgarJwbY5-C08": "FFF"
        },
        "+905469340006": {
          "-LcaHYcsoGA-VT8yvgGf": "L",
          "-LcaH_gtgarJwbY5-C08": "L"
        },
        "05056960007": {
          "-LcaHYcsoGA-VT8yvgGf": "M",
          "-LcaH_gtgarJwbY5-C08": "M"
        }
      }
    }
    

    由于您在数据库结构中使用推送 ID,下面编写的函数在包含推送 ID 的级别上运行,对整个组而不是单个条目执行操作。您可以阅读有关函数 here 的文档并观看有关该主题的一些 Firecasts

    // Import and initialize Cloud Functions and Admin SDKs
    const functions = require('firebase-functions');
    const admin = require('firebase-admin');
    admin.initializeApp();
    
    const ADMIN_DB_REF_PHONE_NUMBER_INDEX = admin.database().ref('/ContactPhoneNumbersIndex');
    
    // Add entirely new contact groups to index
    exports.contactGroups_created = functions.database.ref('/ContactPhoneNumbers/{groupPushId}')
        .onCreate((snapshot, context) => {
          const groupId = context.params.groupPushId;
          
          // prepare atomic write
          const pendingUpdates = {};
          
          const contactsMap = snapshot.val();
          
          for (const phone in contactsMap) {
            if (contactsMap.hasOwnProperty(phone)) {
              let name = contactsMap[phone];
              
              // add data to update
              pendingUpdates[`${phone}/${groupId}`] = name;
            }
          }
          
          // commit the update to the index
          return ADMIN_DB_REF_PHONE_NUMBER_INDEX.update(pendingUpdates);
        });
    
    // Remove deleted contact groups from index
    exports.contactGroups_deleted = functions.database.ref('/ContactPhoneNumbers/{groupPushId}')
        .onDelete((snapshot, context) => {
          const groupId = context.params.groupPushId;
          
          // prepare atomic write
          const pendingUpdates = {};
          
          const contactsMap = snapshot.val();
          
          for (const phone in contactsMap) {
            if (contactsMap.hasOwnProperty(phone)) {
              let name = contactsMap[phone];
              
              // add data to update
              pendingUpdates[`${phone}/${groupId}`] = null; // null will delete data at given location
            }
          }
          
          // commit the update to the index
          return ADMIN_DB_REF_PHONE_NUMBER_INDEX.update(pendingUpdates);
        });
    
    // Handle contact changes
    exports.contactGroups_changed = functions.database.ref('/ContactPhoneNumbers/{groupPushId}')
        .onUpdate((change, context) => {
          const groupId = context.params.groupPushId;
          
          // prepare atomic write
          const pendingUpdates = {};
          
          // prepare changes map
          const changeMap = {};
          
          // add before state to changeMap
          const beforeContactsMap = change.before.val();
          for (const phone in beforeContactsMap) {
            if (beforeContactsMap.hasOwnProperty(phone)) {
              let name = beforeContactsMap[phone];
              changeMap[phone] = { before: name };
            }
          }
          
          // add after state to changeMap
          const afterContactsMap = change.after.val();
          for (const phone in afterContactsMap) {
            if (afterContactsMap.hasOwnProperty(phone)) {
              let name = afterContactsMap[phone];
              
              if (changeMap[phone]) {
                changeMap[phone].after = name;
              } else {
                changeMap[phone] = { after: name };
              }
            }
          }
    
          // look for changes and commit any differences
          for (const phone in changeMap) {
            if (changeMap.hasOwnProperty(phone)) {
              let nameChange = changeMap[phone];
              
              if (nameChange.before != nameChange.after) {
                // changed
                pendingUpdates[`${phone}/${groupId}`] = nameChange.after || null; // use updated value or fallback to null to delete
              }
            }
          }
          
          // commit the update to the index
          return ADMIN_DB_REF_PHONE_NUMBER_INDEX.update(pendingUpdates);
        });
    

    对于您的数据库结构,创建一个类是一项艰巨的任务。一种方法是上一步查看节点树并分组查看联系人,您可以在其中将类包装在值的内部映射或联系人对象列表周围。

    我在下面给出的示例维护内部地图并与之交互。

    不幸的是,Firebase SDK 没有公开类似于自定义比较函数的“序列化”方法,因此您将无法直接将此类与 SetValueGetValue 一起使用。

    上传到数据库:

    ContactGroup mContacts = ...
    DatabaseReference groupRef = mContactGroupsReference.push();
    
    mContacts.setId(groupRef.getKey()); // optional
    groupRef.SetValue(mContacts.toMap());
    

    从数据库下载:

    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
      ContactGroup contacts = new ContactGroup(dataSnapshot);
      // or
      ContactGroup contacts = new ContactGroup(dataSnapshot.getKey(), dataSnapshot.getValue());
    }
    

    这门课不完整。足以让汁液流动,但还有很大的改进空间。

    public class ContactGroup {
      private id = null;
      private Map<String, String> contactMap = new HashMap<>(); // Phone => Name
    
      public ContactGroup() {
      }
    
      public ContactGroup(String id, Map<String, Object> contacts) {
        this.id = id;
        if (contacts == null)
          return;
        for (Map.Entry<String, Object> entry : contacts.entrySet()) {
          contactMap.put(entry.getKey(), entry.getValue().toString());
        }
      }
      
      public ContactGroup(DataSnapshot snapshot) {
        this(snapshot.getKey(), snapshot.getValue());
        // do something else with snapshot? save the ref?
      }
      
      public void add(String name, String phone) {
        contactMap.put(phone, name);
      }
    
      public String getNameForPhone(String phone) {
        return contactMap.get(phone);
      }
    
      public String getPhoneForName(String name) {
        for (Map.Entry<String, String> entry : contactMap.entrySet()) {
          if (entry.getValue() == name)
            return entry.getKey();
        }
        return null;
      }
      
      public getId() {
        return id;
      }
      
      public setId() {
        return id;
      }
      
      @Exclude
      public static ContactGroup fromMap(Map<String, Object> valueMap) {
        return new ContactGroup(null, valueMap);
      }
      
      @Exclude
      public Map<String, Object> toMap() {
        return new HashMap<String, Object>(contactMap);
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2018-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-28
      • 1970-01-01
      • 2012-07-20
      相关资源
      最近更新 更多