Can one do a *reverse* relational query using parse-server? - mongodb

I am working on a system where users can block other users. On the user class, there is a relation called "blockedUsers" which points back to the user table.
If I have a user, and I want to find all the users he has blocked, I do this:
ParseUser user = ParseUser.getCurrentUser();
ParseRelation<ParseUser> relation = user.getRelation("blockedUsers");
ParseQuery query = relation.getQuery();
List<ParseUser> blockedUsers = query.find();
In SQL, this would be something like:
select block.blockee
from block
where block.blocker = 'SomeObjectId'
This would give me the object_ids of all the users who were blocked by user 'SomeObjectId'.
In SQL, I could also reverse this, and say:
select block.blocker
from block
where block.blockee = 'SomeObjectId'
This would give me the object_ids of every user who had blocked user 'SomeObjectId'.
The question is, is there a way to do a query in parse that is similar to the second query? I have looked at ParseRelation.java, and there is nothing in there which is obvious. mongodb uses join tables, but I see no way to join backwards.
Any help?

Yes. It is possible. Something like this should do what you need:
ParseQuery<ParseUser> userQuery = ParseUser.getQuery();
userQuery.equalTo('blockedUsers', blockeeUserObject);
List<ParseUser> blockers = query.find();

Related

Check for existing value inside of Firebase Realtime Database

Hello, I have a problem I created a Registration form and im trying to check if there is any user which have a certain username inside the Firebase Db. I tried to get the reference of all the users.
var users = Database.database().reference("users")
But I don't know how I could check if there is any user with a specified username.
You'll want to use a query for that. Something like:
let query = users.queryOrdered(byChild: "username").equalTo("two")
Then execute the query and check whether the result snapshot exists.
Note though that you won't be able to guarantee uniqueness in this way. If multiple users perform the check at the same time, they may both end up claiming the same user name.
To guarantee a unique user name, you will need to store the user names as the key - as keys are by definition unique within their parent node. For more on this, see some of these top search results and possibly also from here.

Convenient data structure and querying for message application using Firebase Firestore

I've been trying to implement live messaging in my application and I cannot seem to think of a convenient data structure inside Firestore. My current structure looks like this:
collection("conversations").document(id).collection("messages")
Each document holds two attributes user1 and user2 with nicknames of contributors to the conversation. Each document also owns a collection called messages which holds documents where each represents a single message sent with some info.
What I'm trying to do next is to check if the conversation already exists, if not then create it. The problem for me is write a correct query to find out if it exists.
My first idea was: create users array instead which holds nicknames of users and then simply query:
db.collection("conversations").whereField("users", in: ["username1", "username2"])
Problem with this is that it means "where users contains username1 OR username2", but I need it to contain "username1 AND username2".
I tried to be smart and chain the whereField function as following:
db.collection("conversations").whereField("users", arrayContains: "username1").whereField("users", arrayContains: "username2")
Turns out that you cannot use arrayContains more than once in a single query.
After that I came back to the structure as displayed on the screenshot with user1 and user2 and ran a new query:
db.collection("conversations").whereField("user1", isEqualTo: user).whereField("user2", isEqualTo: friend)
This query is ran in a function where user and friend are string parameters holding nicknames of both sender and receiver of the message we're currently sending. Imagine you are sending a message, user is always going to be your nickname and friend the receiver's one. The problem with the query is that you're nickname might be saved under user1 or user2 and receiver's nickname aswell. In either of those situations the conversation exists. How would I have to change the query since I don't know in an advance who will have which position in the query aswell as in Firestore. Running the last query that I included twice while switching user and friend parameter seems very unconvenient.
Any tips or solutions to progress in this problem will be much appreciated!

How can I have an association fetch an existing record?

I'd like to write a factory for a blog post, that doesn't create a new user record for every post, but rather pick a random user from those that already exist. How would I do this?
You could randomly order your table, take a record and assign it to your Post. Bear in mind that there is definitely a cleaner way to do this, but here's one that works, obviously assuming your users are already in your test database.
user = User.order("RANDOM()").take #PostgreSQL
user = User.order("RAND()").take #MySQL
post = create(:post, user: user)

Changing a DB View dynamically according the current user-group

we are currently digging into Amazon Redshift and testing different functionalities.
One of our basic requirements is that we will define different user groups which in turn will be granted access to different views.
One way to go about this would be to implement one view seperately for each user-group. However, since we have a lot of user-groups that share almost the exact same need for information, I'm looking for a way to implement this more dynamically in Redshift.
For instance, let's say I have a user group called users_london and another one called users_berlin. Both will have access to a view called v_employee_master_data which contains the columns employee_name, employee_job_title and employee_city.
Both groups share the same scope of information with one exception - the column employee_city.
In essence, the view should be pre-filtered for a certain value in the column employee_city according to the currently logged-in user-group.
In SQL - something like this:
For the usergroup users_london:
SELECT * FROM v_employee_master_data WHERE employee_city = 'London';
For the usergroup users_berlin:
SELECT * FROM v_employee_master_data WHERE employee_city = 'Berlin';
Now to make the connection back to Amazon Redshift. Does the underlying DB runtime provide an out-of-the-box functionality to somehow catch the currently logged user-group as a form of global variable and alter the SQL-statement according to the value of that variable?
It is possible to do:
get current user
select current_user
find what group it belongs to
select groname from pg_group where current_user_id = any(grolist);
Extract city and capitalize it:
select initcap(substring(groname from 'users_(.*)')) from pg_group where current_user_id = any(grolist);
Now you have your city based on the "user". So just inject it in the view
... WHERE employee_city = initcap(substring(groname from 'users_(.*)') ...

How do I do conditional check, return error, or continue?

A user wants to invite a friend but I want to do a check first. For example:
SELECT friends_email from invites where friends_email = $1 limit 1;
If that finds one then I want to return a message such as "This friend already invited."
If that does not find one then I want to do an insert
INSERT INTO invites etc...
but then I need to return the primary user's region_id
SELECT region_id from users where user_id = $2
What's the best way to do this?
Thanks.
EDIT --------------------------------------------------------------
After many hours below is what I ended up with in 'plpgsql'.
IF EXISTS (SELECT * FROM invitations WHERE email = friends_email) THEN
return 'Already Invited';
END IF;
INSERT INTO invitations (email) VALUES (friends_email);
return 'Invited';
I undestand that there are probably dozens of better ways but this worked for me.
Without writing the exact code snippet for you...
Consider solving this problem by shaping your data to conform to your business rules. If you can only invite someone once, then you should have an "invites" table that reflects this by a UNIQUE rule across whatever columns define a unique invite. If it is just an email address, then declare the "invites.email" as a unique column.
Then do an INSERT. Write the insert so that it takes advantage of Postgres' RETURNING clause to give an answer on success. If the INSERT fails (because you already have that email address -- which was the point of the check you wanted to do), then catch the failure in your application code, and return the appropriate response.
Psuedocode:
Application:
try
invite.insert(NewGuy)
catch error.UniqueFail
return "He's already been invited"
# ...do other stuff
Postgres:
INSERT INTO invites
(data fields + SELECT region thingy)
VALUES
(some arrangement of data that includes "region_id")
RETURNING region_id
If that's hard to make work the first time you try it, phrasing the insert target as a CTE may be helpful. If all else fails, write it procedurally in plpgsql for the time being, making sure the external interface accepts a normal INSERT (so you don't have to change application code later) and sort it out once you know whether or not performance is an issue.
The basic idea here is to let the relational shape of your data obviate the need for any procedural checking wherever you can. That's at the heart of relational data modeling ...somewhat of a lost art these days.
You can create SQL stored procedure for implement functionality like described above.
But it is wrong form architecture point of view. See: Direct database manipulation an anti-pattern?
DB have scope of responsibility: store data.
You have to put business logic into your business layer.