MySql Posting 2 tables - mysql

I am trying to learn mySql DB, I have 2 tables that I am working with, one for the users and one for the cats that the registered users post.
USERS:
+----+---------+------------------+----------+--------+
| id | name | email | password | cats |
+----+---------+------------------+----------+--------+
| 3 | omar | omar#hotmail.com | omar | [] |
| 14 | dana | dana#gmail.com | anad | [] |
| 7 | mama | mami#gmail.com | mama | [] |
| 9 | tata | tata#gmail.com | tata | [] |
+----+---------+------------------+----------+--------+
CATS:
+----+---------+----------------+---------+
| id | name | age | breed | ownerId |
+----+---------+--------+-------+---------+
| 5 | mimi | 2 | Grey | 14 |
| 10 | Negri | 19 | black | 3 |
+----+---------+----------------+---------+
What i want to do is, whenever a cat is posted in the CATS DB I want for that catId to appear in the USERS DB in the owner'sId cats array.
For example the cat Mimi has ID = 5 and the ownerID = 14. If you look in the users table, ID 14 corresponds to user Dana. I want the cats Id(5) to appear in Dana's cats array.
This is the code I have by now : the functions that posts a new cat in the CATS DB.
function addCat (catsData, connection){
let {name, age, breed, ownerId} = catsData;
const mySqlQuery = `insert into cats(name, age, breed, ownerId) values ('${name}', '${age}', '${breed}', '${ownerId}')`;
return new Promise ((resolve, reject) => {
connection.query(mySqlQuery,
function (error, results, fields) {
if(error){
reject(error);
} else {
resolve(results);
}
})
})
};
async function postCatsHandler(req, res, next) {
try {
let data = req.body;
const connection = req.app.get("mySqlConnection");
const addedCatId = await addCat(data, connection);
console.log("addedCatId::", addedCatId);
req.result ='{...data, id : addedCatId}'
next();
}
catch(error){
next(error);
}
};
Any tips or information is greatly valued.
Many thanks.

Related

Laravel 7 select from table with two columns having ids from a Single Table

My requirement?
If i am the logged in user with Id = 1, then through the Messages Table i want to select users from Users Table to whom i sent the message or from whome i received the message.
Table 1: Users
+----+------+-------+
| id | name | email |
+----+------+-------+
| 1 | a | ??? |
| 2 | b | ??? |
| 3 | c | ??? |
| 4 | d | ??? |
| 5 | e | ??? |
| 6 | f | ??? |
| 7 | g | ??? |
| 8 | h | ??? |
| 9 | i | ??? |
| 10 | j | ??? |
+----+------+-------+
Table 2: Messages
+----+---------+-------------+
| id | user_id | receiver_id |
+----+---------+-------------+
| 1 | 1 | 2 |
| 2 | 3 | 1 |
| 3 | 4 | 1 |
| 4 | 1 | 5 |
| 5 | 1 | 3 |
+----+---------+-------------+
User Model
public function messages()
{
return $this->belongsToMany(User::class, 'messages', 'user_id', 'receiver_id');
}
Message Model
public function user()
{
return $this->belongsTo(User::class);
}
So what i have tried so far?
$id = Auth::id();
$users = User::with(['messages' => function($query) use($id){
$query->where('user_id', $id)
->orWhere('received_id', $id)
->orderBy('created_at', 'DESC');
}])->get();
dd($users);
What is the expected result?
Using this query, i am getting all of my 10 users. Although i should only get 4 users(those with id's 2,3,4,5).
If the above query is wrong, or i should follow another method or i should created some sort of relationships Please help.
Hopefully you have understood the question, i am new to Laravel but i am learning.
Probably what you need is three relations(one to many) in the User model. One for sent messages, one for received messages and one for both, like this:
public function messagesSent()
{
return $this->hasMany(Message::class, 'user_id');
}
public function messagesReceived()
{
return $this->hasMany(Message::class, 'receiver_id');
}
public function messages()
{
return $this->messagesSent()->union($this->messagesReceived()->toBase());
}
Then you should be able to get user messages like this: User::with('messages')->get();
I think you should use a join statement or "whereHas" to select users who have any messages.
$id = Auth::id();
$users = User::whereHas('messages', function ($query) use($id){
$query->where('user_id', $id)
->orWhere('received_id', $id);
})
->get();
To have access to "messages" you should add "with" statement too.
Adding my own solution(i.e working) to this question.
User Model
public function sent()
{
return $this->hasMany(Message::class, 'user_id');
}
public function received()
{
return $this->hasMany(Message::class, 'receiver_id');
}
Query
$users = User::whereHas('sent', function ($query) use($id) {
$query->where('receiver_id', $id);
})->orWhereHas('received', function ($query) use($id) {
$query->where('user_id', $id);
})->get();
dd($users);

Counting number of occurrences in column

Example (column A is input, columns B and C are to be auto-generated):
| A | B | C |
+-------+-------+-------+
| Name | Name | Count |
+-------+-------+-------+
| Joe | Joe | 2 |
| Lisa | Lisa | 3 |
| Jenny | Jenny | 2 |
| Lisa | | |
| Lisa | | |
| Joe | | |
| Jenny | | |
I know I can do this with the function below. However, I would like to do it with app scripts. I have tried nesting 2 for loops called (i & j). Where it started with i and j counts until it doesn't match i. Then j equals i so i just jumps to the new start point as to not double count and it kind of worked.
I kept having a problem where it would output a high number on the last 2 iterations or so... I don't think I saved the script after I could not get it to work. any thoughts or help would be appreciated.
The formula I would like to make a script:
=ArrayFormula(QUERY(A1:A16&{"",""},"select Col1, count(Col2) where Col1 != '' group by Col1 label count(Col2) 'Count'",1))
Try this:
It will read column A with header and generate B and C with headers
function pv() {
const ss=SpreadsheetApp.getActive();
const sh=ss.getActiveSheet();
const rg=sh.getRange(2,1,sh.getLastRow()-1,sh.getLastColumn());
const vs=rg.getValues();
let Obj={pA:[]};
vs.forEach(function(r,i){
if(!Obj.hasOwnProperty(r[0])) {
Obj[r[0]]=1;
Obj.pA.push(r[0]);
}else{
Obj[r[0]]+=1;
}
});
let oA=[["Name","Count"]];
Obj.pA.forEach(function(p) {
oA.push([p,Obj[p]]);
});
sh.getRange(1,2,oA.length,2).setValues(oA);
}
This is a simple pivot table

Sequelize - Matching all records of a given entity in mySQL database

I have three MySQL (v8) tables
TABLE 1:
students (contains details of all students)
- id
- full_name
- email
Records:
| id | full_name | email |
|----|-----------|-------------------|
| 1 | John | john#example.com |
| 2 | Adam | adam#example.com |
| 3 | James | james#example.com |
| 4 | Jane | jane#example.com |
TABLE 2:
courses (contains all courses)
- id
- title
Records:
| id | title |
|----|--------|
| 1 | PHP |
| 2 | Python |
| 3 | .Net |
| 4 | HTML |
TABLE 3:
student_courses (this table contains which student has subscribed to what courses)
- student_id
- course_id
Records:
| id | student_id | course_id |
|----|------------|-----------|
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 3 |
| 4 | 3 | 1 |
The problem I am facing here is I need to get a list of all students who have opted for both course ids 1 & 2, which in the above example is "John".
Using sequelize I have tried the following two where clauses, but both giving me incorrect results.
Option 1) This is giving me empty result set
where: {
course_id: {
[Op.and]: [1,2]
}
}
Option 2) This is returning "John" as well as "James". It shouldn't return "James" since he has subscribed to only course id 1.
where: {
course_id: [1, 2]
}
What am I missing here?
Thanks in advance
You can achieve N:M associations by using this, More information can be found here http://docs.sequelizejs.com/class/lib/model.js~Model.html#static-method-belongsToMany
//add required associations
students.associate = (models) => {
students.belongsToMany(models.courses, {
through: 'student_courses',
foreignKey: 'student_id'
});
};
// now query the db like this
db.students.findAll({
where: { full_name : 'john'},
include: [{
model: db.courses,
where: {
id: {
[Op.and]: [1,2]
}
}
}]
})

Laravel query builder doesn't return all prices based on role = customer. Just return 1 price

I'm designing an application where a retailer can add a product with an initial price (store in a products table shown as example), then customers can claim the price of the product purchased from the retailer (this information stores in the prices table shown as example). The retailer then can update / reclaim the price inside the prices table too. and customers can reclaim the price of the product over and over again.
So, I have 2 roles of users called retailer and customer. I'm using Entrust Role package with the default relationship between role and user in the model. Before I explain next, here is my simple database design with all working example (feel free to ask for anything to include):
=============== MY Database Design with sample ===============
table users
__________________________
| id | email | password |
|-------------------------|
| 1 | a#g.com | 123 |
| 2 | b#g.com | 123 |
| 3 c#g.com | 123 |
| 4 d#g.com | 123 |
--------------------------
table roles
______________
|id | slug |
|--------------|
|1 | customer |
|2 | retailer |
----------------
table role_user
__________________
|id_user | id_role|
|------------------|
| 1 | 1 | -> a#gmail.com is a customer
| 2 | 2 | -> b#gmail.com is a retailer
| 3 | 1 | -> c#gmail.com is a customer
| 4 | 1 | -> d#gmail.com is a customer
------------------
table price:
(customer or retailer can claim 1 or more prices):
_____________________________________
|id| user_id | product_id | price |
|----------------------------|
|1 | 1 | 1 |10.00 | -> price claimed by a customer a#gmail.com on product 1
|2 | 2 | 1 |5.00 | -> price claimed by a retailer b#gmail.com on product 1
|3 | 1 | 1 |6.00 | -> price claimed by a previous customer a#gmail.com on product 1
|4 | 3 | 1 |5.00 | -> price claimed by a customer c#gmail.com on product 1
|5 | 2 | 1 |7.00 | -> price claimed by a previous retailer b#gmail.com on product 1
|6 | 3 | 1 |8.00 | -> price claimed by a customer c#gmail.com on product 1
Table products
_____________________________________
|id | user_id| name | Price
|-------------------------------------
| 1 | 1 | Milk | 10.00
| 2 | 2 | Phone | 12.33
| 3 | 1 | computer | 33.44
| 4 | 1 | Banana | 33.22
--------------------------------------
=============== MY Model Relationship ===============
Price model relationship
class Price extends Model
{
public function product()
{
return $this->belongsTo('App\Product');
}
public function user()
{
return $this->belongsTo('App\User');
}
}
Product model relationship
class Product extends Model
{
public function prices()
{
return $this->hasMany('App\Price');
}
}
User model relationship //a user can claim 1 or more prices
class User extends Model
{
public function prices ()
{
return $this->hasMany('App\Price');
}
}
=============== MY Product Controller ===============
This is the tricky part here on how to get the price of all customers except retailer:
class ProductController extends Controller
{
public function show($id)
{
$product = Product::findOrFail($id);
// This query should return all price claimed by customers except retailer. But the problem is, it only return 1 row, the first row which the output is 10.00.
$query_customer =$product->prices()->whereHas('user', function ($q) {
$q->whereHas('roles', function ($q) {
$q->where('slug', 'customer');
});
});
$latest_price_by_customer= $query_customer->value('price');
dd($latest_price_by_customer);
//it just return 1 row: price 10.00
/* It should return the collection that I can do foreach statement. The output should be like this:
10.00
6.00
5.00
7.00
8.00
*/
}
}
The query in the controller above return all prices claimed by customers except retailer. But the problem is, it only return 1 row, the first row which the output is 10.00.
It should output all prices claimed by customers from the prices table like below:
10.00
6.00
5.00
7.00
8.00
Any idea?
Update:
So far I changed my controller codes from this:
$product = Product::findOrFail($id);
$query_customer =$product->prices()->whereHas('user', function ($q) {
$q->whereHas('roles', function ($q) {
$q->where('slug', 'customer');
});
});
$latest_price_by_customer= $query_customer->value('price');
dd($latest_price_by_customer);
to this:
$product = Product::with('prices')->findOrFail($id);
$product_query= $product->prices()->where('product_id', $id) ->whereHas('user', function ($q) {
$q->whereHas('roles', function ($q) {
$q->where('slug', 'customer');
});
})->select('price')->get();
dd($product_query); //display collection and return the correct values
}
I have one small problem here: When loop through the collection
foreach($product_query->prices as $pr)
{
// dd($pr);
// echo $pr->price . ' ___ ' ;
}
I got an error of ErrorException in ProductController.php line 72:
Undefined property: Illuminate\Database\Eloquent\Collection::$prices
but the relationship is exist as shown.
If anyone looking for the answer this is the correct query that returns collection instead of 1 row:
$product = Product::with('prices')->findOrFail($id);
$product_query= $product->prices()->where('product_id', $id) ->whereHas('user', function ($q) {
$q->whereHas('roles', function ($q) {
$q->where('slug', 'customer');
});
})->select('price')->get();
foreach($product_query as $price)
{
echo $price->price;
}

can couchdb do loops

Can couchdb do loops?
Let's say I have a database of interests that have 3 fields
subject1,subject2,subject3. example, cats,nutrition,hair or space,telescopes,optics etc.
A person (A) has 10 interests composed of 3 fields each.
10 more people B,C,D...have 10 interests each composed of 3 subjects each.
When person A logs in I want the system to search for all people with matching interests.
In javascript I would normally loop through all the interests and then find matching ones I guess using
two loops. Then store the matches in another database for the user like "matchinginterests".
Is there any easy way to do this in couchdb compared to mysql -- which seems very complicated.
Thanks,
Dan
I think I understand what you are asking. The answer is pretty straightforward with Map/Reduce.
Say you have the following people documents:
{
"name": "Person A",
"interests" [ "computers", "fishing", "sports" ]
}
{
"name": "Person B",
"interests" [ "computers", "gaming" ]
}
{
"name": "Person C",
"interests" [ "hiking", "sports" ]
}
{
"name": "Person D",
"interests" [ "gaming" ]
}
You would probably want to emit your key as the interest, with the value as the person's name (or _id).
function (doc) {
for (var x = 0, len = doc.interests.length; x < len; x++) {
emit(doc.interests[x], doc..name);
}
}
Your view results would look like this:
computers => Person A
computers => Person B
fishing => Person A
gaming => Person B
gaming => Person D
hiking => Person C
sports => Person A
sports => Person C
To get a list of people with computers as an interest, you can simply send key="computers" as part of the query string.
If you want to add a reduce function to your map, you can simply use _count (shortcut to use a compiled reduce function) and you can retrieve a count of all the people with a particular interest, you can even use that to limit which interests you query to build your relationships.
When person A logs in I want the system to search for all people with matching interests.
SELECT i_them.* FROM interests AS i_me
INNER JOIN interests AS i_them ON (i_them.person != i_me.person) AND
((i_them.subject1 IN (i_me.subject1, i_me.subject2, i_me.subject3)) OR
(i_them.subject2 IN (i_me.subject1, i_me.subject2, i_me.subject3)) OR
(i_them.subject3 IN (i_me.subject1, i_me.subject2, i_me.subject3)))
WHERE i_me.person = 'A'
Is that what you wanted to do?
If you design your tables a little smarter though you'd do it like
SELECT DISTINCT them.* FROM person AS me
INNER JOIN interest AS i_me ON (i_me.person_id = me.id)
INNER JOIN interest AS i_them ON (i_them.subject = i_me.subject)
INNER JOIN person AS them ON (them.id = i_them.person.id AND them.id != me.id)
WHERE me.name = 'A'
Using the following tables
table interest
id integer primary key autoincrement
person_id integer //links to person table
subject varchar //one subject per row.
+-----+-----------+---------+
| id | person_id | subject |
+-----+-----------+---------+
| 1 | 3 | cat |
| 2 | 3 | stars |
| 3 | 3 | eminem |
| 4 | 1 | cat |
| 5 | 1 | dog |
| 6 | 2 | dog |
| 7 | 2 | cat |
table person
id integer primary key autoincrement
name varchar
address varchar
+-----+------+---------+
| id | name | address |
+-----+------+---------+
| 1 | A | here |
| 2 | Bill | there |
| 3 | Bob | everyw |
result
+-----+------+---------+
| id | name | address |
+-----+------+---------+
| 2 | Bill | there |
| 3 | Bob | everyw |
This is how (what you call) 'looping' in SQL works...
First you take person with name 'A' from the table.
me.id me.name me.address
| 1 | A | here |
You look up all the interests
me.id me.name me.address i_me.subject
| 1 | A | here | cat
| 1 | A | here | dog
Then you match everyone elses interests
me.id me.name me.address i_me.subject i_them.subject i_them.person_id
| 1 | A | here | cat | cat | 3
| 1 | A | here | cat | cat | 2
| 1 | A | here | dog | dog | 2
And then you match the person to them's interest (except for me of course)
me.id me.name me.address i_me.subject i_them.subject i_them.person_id them.name
| 1 | A | here | cat | cat | 3 | Bob
| 1 | A | here | cat | cat | 2 | Bill
| 1 | A | here | dog | dog | 2 | Bill
Then you return only the data from them and 'throw' the rest away, and remove duplicate rows DISTINCT.
Hope this helps.