Is it possible to search for an unknown collection that contains a document with identifying fields like an email?
My structure is like this:
Each user gets their own collection based on a unique ID. Each collection contains a user doc and a accounts doc. User doc contains the information about the user that I would like to search for. Accounts doc contains a collection of bank accounts that I want to transfer money between users.
My problem is that I don't want users to type in the long unique id to enter the collection but to type the email of the user that is inside the collection\user document. The email is unique.
Have I just made a bad structure for my project or is there something I can do?
UPDATE
Thanks, Alex and Frank for the feedback.
I went on and changed my structure to as shown:
/users/$uid/accounts/$accountid.
Did a java Query collectionReference = db.collection("users").whereEqualTo("uEmail", userEmail); and saving the document.getId() as a String userId.
I Then use the UserId in a spinner to enable the user to pick an account from the userId accounts collection.
As Alex said, there is no way to load data from a collection (with the client-side SDKs) unless you know the collection name.
But in this case, it seems like your collections are named after the user's UID.
That means that if the user is signed in, you can know their collection by:
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
CollectionReference userCollection = FirebaseFirestore.getInstance().collection(uid);
A few notes:
It is much more idiomatic to store your structure with a top-level collection of users, and then a document for each user under that, and then subcollections for the other data under that. So for example: /users/$uid/accounts/$accountid.
The server-side SDKs do have a method to get a list of collections, for example like this listCollections method in the Node.js SDK. But these SDKs are only to be used in a trusted environment, such as your development machine, a server you control, or Cloud Functions, and not directly on the client. Even with this SDK though, you'll have to iterate the list of collections and check each in turn, because as said before: you can only read data from a collection of which you know the name.
If you're trying to look up the collection/UID for another user than the one who's signed in to the app, you may need to way to map an email address to a UID. Such functionality is not available in the client-side SDKs. But similar as the point above, there is a method getUserByEmail in the Admin SDKs.
Is it possible to search for an unknown collection that contains a document with identifying fields like an email?
No, you should know the name of your collection in order to be able to use it in your reference. There are no wildcards in Cloud Firestore paths to collections/documents. You have to identify every collection and every document by their specific ids.
Related
I have an application where members can post content, but then I have a problem. My problem is that I want to do an activity where the publications of only the author member are shown but Firestore asks me to create an Index to do this, the problem is that the document of each member is based on its UID.
For example:
My UID is: x54asdASD544
Then I try to make this query:
Query query = mMembersDB.document("POST").collection("x54asdASD544").whereEqualTo("type", "public").orderBy("date");
That's when Firestore asks me to create an index, then I create it and it works perfect after creating the index, but if I'm going to do the same, to see the publications of another author, then he asks me to create another index.
For example:
Query query = mMembersDB.document("POST").collection("x54assds").whereEqualTo("type", "public").orderBy("date");
The UID changed, then the previously created index does not work anymore.
Any solution to be able to repair this?
Any way to create indexes automatically?
Each uniquely named collection and subcollection must have its own indexes. You can't share index definitions between collections. They must be defined separately. There is no way to automatically create indexes.
Naming a subcollection based on a UID doesn't sound like a very effective way to model your data. Consider putting all the documents in one collection, put the UID as a field to those documents, and use the UID as a filter to find what you want.
I'm a beginner with LDAP, and I want to use it in the future project with PostgreSQL database.
Suppose that I'll do the authentication with LDAP server, so the user table will not be inserted in PostgreSQL database, in the PostgreSQL database I'll have other tables that must be in relation with the identity of user (that will be retrieved from LDAP) so I have to add a column in each of this tables named uid that store the uid value of the user. Is my idea correct?
What you describe is perfectly fine. Just be aware that which attribute you use as the unique identifier depends on which LDAP directory you are using.
I really only know Active Directory, which does not use the uid attribute at all. AD has a few attributes that are enforced unique:
distinguishedName: Describes where the object is in the directory. It looks something like: CN=Gabriel Luci,OU=Users,DC=domain,DC=com. This is common to LDAP in general, but might be called something different in other LDAP directories.
sAMAccountName: This is commonly referred to as the "username". It must be unique on the domain, but it can be changed.
userPrincipalName: Uses the format username#domain.com. This must be unique in the AD forest, but it can be changed (a "forest" is when there are multiple AD domains in the same organization)
objectSid: (usually just called the SID). It is stored as a byte array, but can be converted to a string that looks like S-1-5-32-##########-###########-##########-#####. This is what is used by Windows in security permissions to grant accounts permissions to files, etc. This cannot be changed.
objectGuid: A GUID that is automatically assigned when the account is created. This cannot be changed.
The first three are human-readable (they will usually have the person's name in it). The other two are not, but they also stay the same for the life of the object (if the person changes their name, the SID and GUID will still be the same).
Which one you use depends on your requirements. The distinguishedName is unique and allows you to bind directly to the object when you need to (as opposed to having to search for the sAMAccountName to find the account). But if you want something that will never change even if the person's name changes, then objectSid or objectGUID is best.
I am using Neo4J to save events from Git-lab web hooks.
An example of the data can be found here https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/web_hooks/web_hooks.md#push-events
One of the nodes is an Author {name,email}
Here the email is the natural unique id.
In Hibernate(JPA) there is an annotation called #Id that i could set on the Author field email (ref to docs).
How can I make Neo4J OGM to persist/merge based on email instead of it's id?
One of the fastes/easiest solution would be to use constraints:
Create CONSTRAINT ON (a:Author) ASSERT a.email IS UNIQUE
This way, neo4j will ensure constraint is respected, and you don't have to implement uniqueness on server side, since database is doing it.
In an ETL tool you would reasonably expect to able to define your source keys/identities. Neo4j OGM is not really an ETL tool, but if you want to use it as a data importer, you have a couple of options.
The first is to manage the key-mappings yourself. Of course, this may be impractical, depending on volumes and other considerations. The second is always try to fetch a given object from the graph via its email address before saving any item from your event feed.
I have a couple of comments.
Administrator seems to be the value of the name property, not the email property. Are you sure the 3 Administrator nodes in you image actually have the same email property value? To make the neo4j Browser show the email values, set the caption for the Author nodes to email instead of name.
Aside from the above, it looks like you have already tried this Cypher query, but are getting what seem to be duplicates:
MERGE (n:Author {name: {name}, email: {email}})
RETURN n
That could be explained if it is possible for the input data to contain multiple names for the same email address. In that case, the following query should prevent "duplicate" Author nodes. If an Author with the parameterized email address already exists (regardless of its name value), it just returns the existing node (without changing its name); otherwise, it creates a new Author node with the parameterized email and name properties. This solution would mean that only the first name encountered for an email address will be stored in the DB.
MERGE (n:Author {email: {email}})
ON CREATE SET n.name = {name}
RETURN n
I am developing an Android app which needs to know when a contact is added/updated/deleted.
So I read several posts for it. I understand that we can get notified through Content observers whenever a contacts gets changed, but we can't get which contacts have been added/updated/deleted. So I have read the official APIs and prepared my design how to capture that particular contact.
So what I thought at the start
We will store all the contact IDs, deleted flag and version
Whenever contacts get changed I will get my table's row count and row count from Android's system.
If my rowcount is less than systems row count then a contact has been deleted.
If my rowcount is greater than systems row count then a contact has been added.
And if these are not the cases then one of the contacts version has been changed.
I have also learned that Android doesn't delete the contact if it is deleted by user, but it sets 0 on deleted flag. So in these cases the row count will be same.
Android also changes the row ID of a contact many times as stated in the official docs. So how can we uniquely identify them like lookup uri and if not then we have to put observer for that also.
So I want to know whether the above is correct? And in the case a contact is added will it be added to the last row of cursor or not means if I check the last row of system database for contacts will it give me the contact added or not.
Let me explain as much as I could. Basically your policy looks pretty good, but actually it is bit more complex than you thought.
On Android, a contact can be associated with several raw contacts, which may be provided from many data providers, such as Google, Facebook, Skype and so on. For example, if one of your friends in your local contacts is also using Skype, there are two raw contacts existing separately in ContactContracts.RawContacts, but they will be aggregated automatically and show up just as one contact when you query to ContactsContract.Contacts.
That is also why it's hard to identify a contact uniquely, because you can split or join them anytime you want. LOOKUP_KEY isn't very handy for this case.
Many apps except Google only provide a one-way sync, i.e. only from service to contacts, so they are read-only. In this case, the deleted flag will not be used and simply deleted during their synchronization process. Thus, you can not simply rely on the flag.
Though there isn't a good simple solution, I guess it's much easier to achieve what you want, if you observe for a specific RawContacts, not Contacts. Hope this helps your understanding.
I think the best practice is to monitoring whenever a contact has aggregate to another one and identify them by the contactName, not the _ID or CONTACT_ID.
Take a look at this possibly contacts operations:
Insert
A Contact cannot be created explicitly. When a raw contact is inserted, the provider will first try to find a Contact representing the same person. If one is found, the raw contact's CONTACT_ID column gets the _ID of the aggregate Contact. If no match is found, the provider automatically inserts a new Contact and puts its _ID into the CONTACT_ID column of the newly inserted raw contact.
Update
Only certain columns of Contact are modifiable: TIMES_CONTACTED, LAST_TIME_CONTACTED, STARRED, CUSTOM_RINGTONE, SEND_TO_VOICEMAIL. Changing any of these columns on the Contact also changes them on all constituent raw contacts.
Delete
Be careful with deleting Contacts! Deleting an aggregate contact deletes all constituent raw contacts. The corresponding sync adapters will notice the deletions of their respective raw contacts and remove them from their back end storage.
Query
If you need to read an individual contact, consider using CONTENT_LOOKUP_URI instead of CONTENT_URI.
If you need to look up a contact by the phone number, use PhoneLookup.CONTENT_FILTER_URI, which is optimized for this purpose.
If you need to look up a contact by partial name, e.g. to produce filter-as-you-type suggestions, use the CONTENT_FILTER_URI URI.
If you need to look up a contact by some data element like email address, nickname, etc, use a query against the ContactsContract.Data table. The result will contain contact ID, name etc.
The problem, though, is that you could have two 'Phillip Morris' in your contact list that aren't the same person.
For further information, see this section of Android Classes Documentation.
basically I am wondering how you would go about in Couchdb as you would in MysQL: storing username, password in one table and link the user id as foreign key on another table of tasks?
should I just use mysql for the user authentication part and couchdb to store lots of user submitted documents? so create a random unique token to link each user to their "documents" on couchdb?
also I am looking to store Java objects to the couchdb, and retrieve them to be used directly in my application. which Java-couchdb library does this? Ektorp's example is seems more complicated compared to couchdb4j.
I do not know Java very well, but I suggest use the most simple tool you find. CouchDB is very simple and usually it is most beneficial to access it with simple tools too.
Yes, if you will have many relationships in the data, MySQL will help. However CouchDB can do some simple has-many queries.
First, there is view collation. You use map/reduce, and for every "child" document, you emit a key pointing to the parent document. When you query for ?key=parent then you get a long list of children. (The wiki explains it pretty well.)
Secondly, I suggest the article What's new in CouchDB 0.11 which shows how to use document _ids to link between two documents.
Good luck!