I'm trying to get my grips around the structuring of Datastore. Sorry in advance for the n00bness but I really can't get my head around it...
Consider a typical dating app which would use google cloud's datastore as a "database".
Suppose we have:
users
photos
swipes
matches
In a typical SQL style database I might choose to have (amongst other things):
A user table with a primary key of id
A photo table with a foreign key of user_id to link to the user whose photo it is
A swipe table for each individual swipe by any user against any other user it would have 2 foreign keys, swiper and swiped
a match table where we add a new entry if 2 people both swipe right on each other.
Would you structure it similarly in datastore by having those 4 entity types? If so how do you deal with the "foreign keys"?
Or would you nest some of those within a document e.g each user has a list of photos nested within it, or a list of all their swipes/matches, ensuring that both users in a match have that reflected?
I typically prefer interacting with Datastore via the ndb library (if you're not using Python, you might still get an idea of how to apply the following suggestion in your own runtime).
Using the ndb library, I could potentially see myself going with what you have where the 'foreign keys' you refer to would be implemented as a ndb.KeyProperty.
A very rough profile of what you might have would be
# This is your user KIND
class User(ndb.Model):
....
# This is your photo KIND
class Photo(ndb.Model):
# This ties each record in Photo to a person in your User table
user = ndb.KeyProperty(kind="User", required=True)
....
# This is your Swipes KIND
class Swipes(ndb.Model):
# This ties each swiper to a person in your User table
swiper = ndb.KeyProperty(kind="User", required=True)
# This ties each swiped to a person in your User table
swiped = ndb.KeyProperty(kind="User", required=True)
....
From the UI, you can click on any column defined as ndb.KeyProperty and it will open up the underlying record. In your code, you can directly run a query (do a GET) to return the details of the underlying record.
Let's say you used the above model, then to run queries where you wish to list photos and the name of the user who posted them or to list swipes and who swiped to who, I would use tasklets to have the queries run concurrently & asynchronously. See the tasklets section on the old Python2 NDB documentation for a worked example
Related
my flow:
User A selects user B in the user list:
system needs to check if a room for these two users exists, if not create unique room name and then join both users to the room
if exists, then just join users to the room they were already in and populate the chat with previous msges
Now what I am stuck at is how to exactly do it. Few options I am playing with in my head:
a) First how do i create the unique name that ties both users? Sure I can use string combination for both users, for example user A clicks user B --> "A&B", but this won't work when user B clicks user A, because that will be "B&A". I am struggling with creating dynamic unique names that could be applied to both.
b) do I keep an array with the two users info in the specific room saved in DB, and then check the array if user exists in it already? if so just use that room id as the room name? What is the best flow to save created rooms? Do i save by room name, which I guess would act as unique Id as well?
c) should I be checking the DB EVERYTIME user clicks another user to start a chat just to check if a room exists or not?
I know how to create rooms and all that jazz but what I am really struggling with is how to dynamically create room names so that its the same whether A clicks B or B clicks A and how to from a pseudo code level, store created rooms in DB and check for many users.
Here's an idea: Store the room in your database as a document that contains fields user1 and user2, which will contain the IDs of these users. Specifically, ensure that user1 < user2. When you need to query for this document later, you can do db.rooms.findOne({user1: smallerId, user2: largerId}). Then you can either store the room name and not use it in your queries, or you can even generate the displayed room name dynamically at runtime.
This has the benefit of not only guaranteeing the structure of a room document, but making your queries more efficient as well (you're comparing binary vs. comparing strings). There's also the benefit of not breaking the query when a user's name changes.
In general it's recommended that a document A that's associated with a different document B should refer to document B by an immutable ID, rather than by a mutable name. In this case since a room is associated with two users, have room refer to each user's ID.
I've done some small projects in Access before, and I'm having an issue wrapping my head around something a bit more complicated.
I'm setting up a database to track boats. (I'll spare you the story of why.) I have two main tables: Table A is all of the information on the individual boats, table B is all of the owner's information. For ease of use on the users, I need to create a form that mimics the hand written form people filled out that the user needs to enter into the database.
This seems simple enough, and if I was using a simple DB as I have in the past, I wouldn't be here looking for help. BUT, since the form has the boat and owner information, I need the form to always enter the boat information into Table A, but when the owner information is entered, I need to check Table B to see if the person is already in the table, and if they're not, add the owner information to Table B, and associate the two records, OR if the check shows the owner information is already in Table B, I need it to associate the new boat information being put into the form, and thus being put into table A with the owner information that is already in table B so I don't wind up with duplicate data.
This probably sounds more complicated when I explain it than it actually is, but since I'm stuck with the handwritten form that's already created, I'm trying to make this as simple as I can on the end user. Basically, since one person can own more than one boat, I need it to check before adding new user info, and get the boat info to either associate with the new owner entry, or the one that already exists if that's the case.
Any and all assistance is greatly appreciated.
Make the entry form unbound.
Check the owner data against your existing table.
Then if the owner does not yet exist add both an owner record and a boat record, otherwise just add the boat record with the existing owner ID.
I have a specific question regarding the utilization of three tables in a database. Table 1 is called Personnel, and lists the names of the staff.
Tables 2 and 3 are identical, just listing two different types of overtime (long and short), along with the hours of the OT, Date of the OT, and Assigned to/Picked fields that are empty.
Here is the idea, I just dont know how to implement it. I would like to create a form for people to enter their OT picks, then automatically move to the next person on the list. So Rich Riphon, as an example, would be up first, would click on the link I would send, and a form would open up, showing his name, populated by the first table, and showing two drop down menus, populated from the Long OT and Short OT tables. He would select one from each (or None, which would be a option) and Submit it.
The form action would be to place his name in the Assigned field for the OT he picked, and place a Yes in the Picked field.
When the next person in the list opens the form, it has moved down to number 2 on the Personnel list, Cheryl Peterson, and shows her the remaining OT selections (excluding those that have a Yes in the Picked column).
Any suggestions or comments or better ways to do this would be appreciated.
First, I don't think ms access would be able to (easily) kick off the process based on a hyperlink. You may be able to do something by passing a macro name to a cmd prompt but it would take some mastery to get it working properly. Could you instead create a login form to get the current user? If you do that you don't really need to display the personnel list, just keep track of who has not yet responded to the OT request. Essentially at that point all you would need on your form is a listing of the available OT and a button that creates the assignment. Also it may be easier (and a better design) to only have one table for the OT listings and add a column for the type of overtime (long/short).
What if Cheryl isn't the 2nd person to get the form? Your concept goes out the window.
Instead, I would keep a table of all user names, and their security level. managers can see everything, individual users can only see their record. This would be done by using a query behind the OT Picks form, and either filtering by the current user or not filtering at all. I have done many of these types of "user control" databases and they all have worked well.
As for the actual OT tracking, I agree with Steve's post in that it should be done in one table This would be the preferred method of a concept referred to as "normalizing data". You really want to store as little data as possible to keep the size of your database down. As an example, your Login table would have the following fields:
UserID
FirstName
LastName
SecurityLevel
Address1
Address2
City
State
Phone
Etc... (whatever relevant info pertains to that person)
Your OT table would look like this:
UserID
OTDate
OTHours
OTType
Etc... (whatever else is relevant to OT)
You would then join those 2 tables on the UserID fields in both tables any time you needed to write a query to report OT hours or whatever.
I am trying to work around a limitation that Filemaker 12 seems to have. In a value list that links to an ODBC attached SQL Server database, it doesn't display every piece of data. If there are 2 people with the same last name for example, it only displays the first person with that last name in the list. This is verified by the following in the Filemaker documentation (which I found after a lot of digging)
If the value list is defined to display information from two fields, items will not be duplicated for the field on which the value list is sorted. For example, if the value list displays information from the Company field and the Name field, and if the values are sorted by the Company field, only one person from each company will appear in the value list.
Portals on the other hand will find all the related data, I just don't understand how do something with the data once I get it in the portal. I essentially thus wish to use a portal AS my drop-down value list, and then to use it as I would have a value list (which is then to act as the key to do the rest of the lookups on the page to fill out the invoice.
The major issue here (other than this maddening choice Filemaker seems to make) is that the external file I am pulling the data from is an ODBC mounted SQL Server file, so I can't do something easy like a calculated field which would give me last name & " " & first which would make almost every person unique. Filemaker won't let me do that because it says I can't do that with a field that is not indexed. Any help would be greatly appreciated!
Assuming that we're starting with table MyTable and we're trying to get a ID from the People table for the selected person, which we'll call ID so that we can put it into MyTable::PersonID
Start by creating a new Table Occurrence of your People table and call it PeopleWhoCanBeSelected. If you want every person in the People table you can connect it to MyTable with the X relationship. If you want to show just a subset of the people you can build a different relationship.
Now, on a layout displaying records from MyTable you will make a portal showing records from the PeopleWhoCanBeSelected table.
In the portal put a button. When that button is pressed use the Set Field script step:
Set Field MyTable::PersonID to:
PeopleWhoCanBeSelected::ID
That should do it. You can make the button an invisible overlay on the entire portal record if you like, so that the user clicks on "the name" instead of "the button next to the name".
Now, if you want to pull additional data through to the MyTable record, you'll need to create a second Table Occurrence, called People with the relationship MyTable::PersonID = People::ID. Then you can get information on the specifically chosen person through that relationship.
I'm working on a voting site and I'm wondering how I should handle votes.
For example on SO when you vote for a question (or answer) your vote is stored, and each time I go back on the page I can see that I already voted for this question because the up/down button are colored.
How do you do that? I mean I've several ideas but I'm wondering if it won't be an heavy load for the database.
Here is my ideas:
Write an helper which will check for every question if a voted has been casted
That's means that the number of queries will depends on the number of items displayed on the page (usually ~20)
Loop on my items get the ids and for each page write a query which will returns if a vote has been casted or NULL
Looks ok because only one query doesn't matter how much items on the page but may be break some MVC/Domain Model design, dunno.
When User log in (or a guest for whom an anonymous user is created) retrieve all votes, store them in session, if a new vote is casted, just add it to the session.
Looks nice because no queries is needed at all except the first one, however, this one and, depending on the number of votes casted (maybe a bunch for each user) can increase the size of the session for each users and potentially make the authentification slow.
How do you do? Any other ideas?
For eg : Lets assume you have a table to store votes and the user who cast it.
Lets assume you keep votes in user_votes when a vote is cast with a table structure something like the below one.
id of type int autoincrement
user_id type int, Foreign key representing users table
question_id type of int, Foreign key representing questions table
Now as the user will be logged in , when you are doing a fetch for the questions do a left join with the user_id in the user_votes table.
Something like
SELECT q.id, q.question, uv.id
FROM questions AS q
LEFT JOIN user_votes AS uv ON
uv.question_id = q.id AND
uv.user_id = <logged_in_user_id>
WHERE <Your criteria>
From the view you can check whether the id is present. If so mark voted, else not.
You may need to change your fields of the questions table and all. I am assuming you store questions in questions table and users in user table so and so. All having the primary key id .
Thanks
You could use a combination of your suggested strategies.
Retrieve all the votes made by the logged in user for recent/active questions only and store them in the session.
You then have the ones that are more likely to be needed while still reducing the amount you need to store in the session.
In the less likely event that you need other results, query for just those as and when you need to.
This strategy will reduce the amount you need to store in the session and also reduce the number of calls you make to your database.
Just based on the information than you've given so far, I would take the second approach: get the IDs of all the items on the page, and then do a single query to get all the user's votes for that list of item IDs. Then pass the collection of the user's item votes to your view, so it can render items differently when the user has voted for that item.
The other two approaches seem like they would tend to be less efficient, if I understood you correctly. Using a view helper to initiate an individual query for each item to check if the user has voted on it could lead to a lot of unnecessary queries. And preloading all the user's voting history at login seems to add unnecessary overhead, getting data that isn't always needed and adding the burden of keeping it up to date for the duration of the session.