Get array of friend names with friend id's from MongoDB - html

I'm making MEAN app for the first time. I managed to insert users into MongoDB. Each user looks like:
{
"name":"My Name",
"country":"Italy",
"friends":"5922c66b4e708e27a02b7937"
}
My first question is, how to manualy insert more than one friend (how to separate them via Postman)?
Then I have html page to show those informations about user, so I display his friends that way:
<td>{{user.userFriends}}</td>
When I will have more than one firend in database, how to display number of friends instead of their IDs?
Thanks for help!
EDIT: Solved the first part with
{
"friends":["5922c66b4e708e27a02b7937","5922c66b4e708e27a02b7938"]
}

To get Mongo to calculate the number of friends a user has, you can use the $size operator on the friends array. You need to use the aggregation pipeline to do this though. Otherwise, you can just calculate the length of the array yourself. For more details on the $size operator and the aggregation pipeline, see here: https://docs.mongodb.com/manual/reference/operator/aggregation/size/

Related

How would you model a collection of users and friends in Firebase?

I'm trying to create a database (json) with Firebase.
I searched the docs and the net but couldn't find a clear way to start.
I want to have a database of users.
each user (represented as UID) should have a nickname and a list of friends.
I tried making a .json file that looks like this:
{
users:{
}
}
and adding it to the Firebase console to get started but it wouldn't work.
How can I do it?
the database should look like this:
{
users:{
UID:{
nickname: hello
friends: UID2
}
UID2:{
nickname: world
friends: UID
}
}
I don't know if I got that right, so I would really appreciate any help you guys could give me at this subject.
Thanks in advance!
Seems like a good place to start. I would make two changes though.
keep the list is friends separate
keep the friends as a set, instead of a single value or array
keep the list is friends separate
A basic recommendation when using the Firebase Database is to keep your data structure shallow/flat. There are many reasons for this, and you have at least two.
With your current data structure, say that you want to show a list of user names. You can only get that list by listening to /users. And that means you don't just get the user name for each user, but also their list of friends. Chances that you're going to show all that data to the user are minimal, so that means that you've just wasted some of their bandwidth.
Say that you want to allow everyone to read the list of user names. But you only want each user to be able to read their own list of friends. Your current data structure makes that hard, since permission cascades and rules are not filters.
A better structure is to keep the list of user profiles (currently just their name) separate from the list of friends for each user.
keep the friends as a set
You current have just a single value for the friends property. As you start building the app you will need to store multiple friends. The most common is to then store an array or list of UIDS:
[ UID1, UID2, UID3 ]
Or
{
"-K.......1": "UID1"
"-K.......5": "UID2"
"-K.......9": "UID3"
}
These are unfortunately the wrong type for this data structure. Both the array and the second collection are lists: an ordered collection of (potentially) non-unique values. But a collection of friends doesn't have to be ordered, it has to be unique. I'm either in the collection or I'm not in there, I can't be in there multiple times and the order typically doesn't matter. That's why you often end up looking for friends.contains("UID1") or ref.orderByValue().equalTo("UID1") operations with the above models.
A much better model is to store the data as a set. A set is a collection of unordered values, which have to be unique. Perfect for a collection of friends. To store that in Firebase, we use the UID as the key of the collection. And since we can't store a key without a value, we use true as the dummy value.
So this leads to this data model:
{
users:{
UID:{
nickname: hello
}
UID2:{
nickname: world
}
}
friends:{
UID:{
UID2: true
}
UID2:{
UID: true
}
}
}
There is a lot more to say/learn about NoSQL data modeling in general and Firebase specifically. To learn about that, I recommend reading NoSQL data modeling and watching Firebase for SQL developers.
I keep a collection of Friends where the users field is an array of 2 user ids: ['user1', 'user2'].
Getting the friends of a user is easy:
friendsCollection.where("users", "array-contains", "user1").get()
This should get you all documents where user1 appears.
Now the tricky part was on how to query a single friend. Ideally, firebase would support multiple values in array-contains, but they won't do that: https://github.com/firebase/firebase-js-sdk/issues/1169
So they way I get around this is to normalize the users list before adding the document. Basically I'm utilizing JS' truthiness to check what userId is greater, and which is smaller, and then making a list in that order.
when adding a friend:
const user1 = sentBy > sentTo ? sentBy : sentTo
const user2 = sentBy > sentTo ? sentTo : sentBy
const friends = { users: [user1, user2] }
await friendsCollection.add(friends)
This basically ensures that whoever is part of the friendship will always be listed in the same order, so when querying, you can just:
await friendsCollection.where("users", "==", [user1, user2]).get()
This obviously only works because I trust the list will always have 2 items, and trust that the JS truthiness will work deterministically, but it's a great solution for this specific problem.

I can't get an e-mail of a specific contact

Here is my story:
I'm writting a script that permits to see every users in an array of group (I mean, you select 2 group, it show every users in one of these two groups). It also do some other treatment. But it's OK for this part.
Everything seems to work correcly. Except for only one user.
The idea is, I have to get the e-mail of a user, to then compare users'e-mail got in a former group, to see if this user is (or not) already listed ( in order to avoid duplicate).
The user (this one only) won't use my function. I supposed it was a group, but it really is a user.. I'm pretty sure it is an option to select ( or not) in the user's preference, but which one?
PS: here is the error quote
TypeError: Fonction getEmail introuvable dans l'objet
(TypeError: getEmail function not found in object)
And here is the code I use in order to get e-mails:
for(var i in objuser){
for(var j in objuser[i])
{
objuser[i][j]=objuser[i][j].getEmail();
}
}
Objuser is a list of User Object. First dimension (I) is the group, second dimension (j), is users of the "I" group.
PROBLEM NOT SOLVED:
the reason:
I have 2 functions that do treatments. Theses Two function need an array, that another function create (which is long to execute). My code is done in such a way, if i execute consecutively these 2 treatment functions with the same array, the second to be played use an incorrect array.
So i clone it with :
var groupsUser2 = JSON.parse(JSON.stringify(groupsUser));
but, now that i dont use anymore email adresses ( i mean String), but direct Users (i mean Object), the former code don't clone correctly:
array1 : user's array (Objects)
array2 = JSON.parse(JSON.stringify(array1))
log(array1) :[blabla1#...com,blabla2#...com,blabla3#...com, .....]
log(array2) :[{},{},{}………]
SO.... Here is the new question: Is there a simple way to copy an Object's array ?
Here is the former question: What rights configuration unallow me to use the getEmail() function for a specific contact?
I need an answer just for one of these two questions, and i'll be able to correct my problem. Any idea guys???????
never use "for x in array" its bad use of javascript on an array because the array has the "length" property which is a number and not the object your loop expects.
instead use " for (i=0;...." or forEach.
Well, I was using getEmail() function in order to compare users got in one group, to others got in another group , so that i can avoid duplicates.
I was checking with IndexOf() if the user adress were in the array of the other group's users.
I don't know why , but now it works even if i don't get the e-mail of the user. So , the problem that was happening for one user can't happen anymore.
Conclusion: Problem solved. Thx mates
I thought about a solution: try .. catch, so that the email which won't be get, will be potentially duplicated because I will not be able to find the user if already displayed or not without his e-mail, but at least the script will not crash.

Restkit: Post an array of id's instead of the complete objects

I have a case where I need to post and array of numbers to the server side. E.g:
I have an order that have a list of products with one to many relation ships.
The question is how to post only array of id's for current order:
Now I have such result:
{"orders":[{"id":0,"Products":[{"productId":6},{"productId":7},{"productId":5},{"productId":3}]},{"id":1,.....]}
But I want to make it
{"orders":[{"id":0,"Products":[6,7,5,3]},{"id":1,.....]}
Any ideas ?
Update 1
I think I have found a solution
I have add method that fetch id's of my order products it's look like this
-(NSArray *)productsIds {
return [self.products.array valueForKeyPath:ProductAttributes.productId];
}
and add such a thing to my mapping code part.
[orderSerializationMapping addAttributeMappingsFromDictionary:#{#"productsIds" : #"Products"}];
And now result is
{"orders":[{"id":5,"Products":[17,13,16,11,12,19]},......]
You don't need add a method to fetch the id's. Setup your mapping like this:
[orderSerializationMapping addAttributeMappingsFromDictionary:#{#"products.productID": #"Products"}];

Laravel 4 Eager Loading filtering and selecting only matching results

I'm trying to output the filter results with only matching elements.
I have two tables (in the real project, which will be 5), let's say companies and projects. A company may have more than one project or may not have any.
These are the relations:
/app/models/Company.php
<?php
class Company extends Eloquent {
public function projects() {
return $this->hasMany('Project','companyID');
}
protected $table = 'companies';
}
/app/models/Project.php
<?php
class Project extends Eloquent {
public function companies() {
return $this->belongsTo('Company','companyID');
}
}
What I want to do is, I want to get results of them both but only with matching parameters.
I've tried this:
return Company::with(array('projects'=>function($query){
$query->where('id',99); //project's id is 99
}))->get();
This is the output JSON
If I change the value from 99 to 1 (there is a result with products.id of 1), it changes into this:
I only want to get the second result from the second JSON i've posted.
As you can see in the second JSON (I'm using this parser to check), all companies are loaded regardless of the project, and only the rows matched have the object projects.
There will be more 'with's and I don't know how to filter only matching elements.
I also tried having() inside closure, but it's still same:
$query->having('projects.id','=',99);
Is there a way to filter only matching results (without using a loop) which the output will only include the results having the matched projects object?
Edit: Actually, 5 tables will be filtered.
companies, projects, works, users and user_works
Let's say;
"Companies" have many projects.
"Projects" have many works
"Works" have many users, also "Users" may have more than one work (pivot table user_works).
All relations are set correctly from models.
I want to do a global searching to these.
Something like: "Bring me the user id 1's works which has company id of 5 and project id of 4", but none of the fields are mandatory.
So these are also valid for searching: "Bring me everyone's works on project id of 2", or "bring me id 2's works", or "bring me all the works starting from today", "bring me the id 1's works on project 2", "Bring me this year's works done of company id 1".
Thanks in advance
Using whereHas() is the solution on my case. It filters relation and affects the results returned in the main query.
If you have the id of the project, would it make more sense to go that route? $project = Project::find(99); and then the company variables would be accessible with $project->companies->name;
It would make more sense to rename the companies() function to company() because a project will only ever belong to one.

Logical Column in MySQL - How?

I have a datamodel, let's say: invoices (m:n) invoice_items
and currently I store the invoice total, calculated in PHP by totalling invoice_items, in a column in invoices. I don't like storing derived data as it paves the way for errors later.
How can I create a logical column in the invoices table in MySql? Is this something I would be better handling in the PHP (in this case CakePHP)?
There's something called Virtual Fields in CakePHP which allows you to achieve the same result from within your Model instead of relying on support from MySQL. Virtual Fields allow you to "mashup" various data within your model and provide that as an additional column in your record. It's cleaner than the other approaches here...(no afterFind() hacking).
Read more here: http://book.cakephp.org/view/1608/Virtual-fields
Leo,
One thing you could do is to modify the afterFind() method in your model. This would recalculate the total any time you retrieve an invoice (costing runtime processing), but would mean you're not storing it in the invoices table, which is apparently what you want to avoid (correct if I'm wrong).
Try this:
class Invoice extends AppModel {
// .. other stuff
function afterFind() {
parent::afterFind();
$total = 0;
foreach( $this->data['Invoice']['InvoiceItems'] as $item )
$total += ($item['cost'] * $item['quantity']);
$this->data['Invoice']['total'] = $total;
}
}
I may have messed up the arrays on the hasMany relationship (the foreach line), but I hope you get the jist of it. HTH,
Travis
Either you can return the derived one when you want it via
SELECT COUNT(1) as total FROM invoice_items
Or if invoices can be multiple,
//assuming that invoice_items.num is how many there are per row
SELECT SUM(num) as total FROM invoice_items
Or you can use a VIEW, if you have a certain way you want it represented all the time.
http://forge.mysql.com/wiki/MySQL_virtual_columns_preview
It's not implemented yet, but it should be implemented in mysql 6.0
Currently you could create a view.