Eloquent SUM and GET Latest Relationship Data - sql

I have two models User and Transaction. The User model has a one-to-Many relationship with Transaction:
I am trying to return
some data from the User table
sum of all amount in the Transaction table that belongs to the user
transaction hash from the most recent transaction
Expected response:
{
"name": "User A",
"image": "images/user-a.png",
"last_transaction_hash": "79s8s900",
"total_transaction_sum": "30000"
},
{
"name": "User B",
"image": "images/user-b.png",
"transaction_hash": "a102920",
"total_transaction_sum": "23000"
}
What I have tried:
$users = User::withCount([
'transactions as total_transaction_sum' => function ($q) {
return $q->select(DB::raw("SUM(amount) as amount"));
},
])
->orderByRaw('total_transaction_sum DESC NULLS LAST')
->get();
With the above query I can return data for (1 & 2) but I find it hard to select the specific columns that I want to see and I still can't figure out how to return transaction hash of the latest transaction (3).

you can use Query builder to achive this in sort line like this
$users = User::select(\DB::raw('user.name, user.image, SUM(transactions.amount) as total_transaction_sum'))
->join('transactions', 'users.id', '=', 'transactions.user_id')
->orderByRaw('total_transaction_sum DESC NULLS LAST')
->get()
->groupBy('id')
->map(function ($row) {
$opt = $row;
$opt['transaction_hash'] = optional($row->last())->id;
return $opt;
})->values();
ref link https://laravel.com/docs/8.x/queries#joins

Related

How can i get keys from each object in array (postgresql)?

I done
let statuses = await t.any(`SELECT DISTINCT status FROM mails`)
and got
"statuses": [
{
"status": "error"
},
{
"status": "success"
}
]
How can I get array with keys of objects ? ['error', 'success'] ?
Assuming status is a jsonb column (which it should be), you can do:
select distinct st.status
from mails m
cross join jsonb_array_elements(m.status -> 'statuses') as st(status)
If status is a json column you will need to use json_array_elements() instead

Returning unknown JSON in a query

Here is my scenario. I have data in a Cosmos DB and I want to return c.this, c.that etc as the indexer for Azure Cognitive Search. One field I want to return is JSON of an unknown structure. The one thing I do know about it is that it is flat. However it is my understanding that the return value for an indexer needs to be known. How, using SQL in a SELECT, would I return all JSON elements in the flat object? Here is an example value I would be querying:
{
"BusinessKey": "SomeKey",
"Source": "flat",
"id": "SomeId",
"attributes": {
"Source": "flat",
"Element": "element",
"SomeOtherElement": "someOtherElement"
}
}
So I would want my select to be maybe something like:
SELECT
c.BusinessKey,
c.Source,
c.id,
-- SOMETHING HERE TO LIST OUT ALL ATTRIBUTES IN THE JSON AS FIELDS IN THE RESULT
And I would want the result to be:
{
"BusinessKey": "SomeKey",
"Source": "flat",
"id": "SomeId",
"attributes": [{"Source":"flat"},{"Element":"element"},{"SomeOtherElement":"someotherelement"}]
}
Currently we are calling ToString on the c.attributes, which is the JSON of unknown structure but it is adding all the escape characters. When we want to search the index, we have to add all those escape characters and it's getting really unruly.
Is there a way to do this using SQL?
Thanks for any help!
You could use UDF in cosmos db sql.
UDF code:
function userDefinedFunction(object){
var returnArray = [];
for (var key in object) {
var map = {};
map[key] = object[key];
returnArray.push(map);
}
return returnArray;
}
Sql:
SELECT
c.BusinessKey,
c.Source,
c.id,
udf.test(c.attributes) as attributes
from c
Output:

TypeORM activeRecord style query for "where (a & b) or (c & d)"?

I want to use TypeORM to run a query like
... WHERE (a=1 && b=true) OR (a=2 && b=false)
I see a bunch of references to doing this in the QueryBuilder style, but I need to know how to do this using the ActiveRecord style.
You can do this by providing an array of objects to the where: property:
Item.find({
where: [
{ user: { id: userId }, confirmed: "true" },
{ user: { id: userId }, status: "active" }
]
});
The query above would find items that belong to a user where
user matches user id AND is confirmed, or...
user matches user id AND is active
I do not know about TypeORM, however I found this on ruby on rail active query methods:
https://guides.rubyonrails.org/active_record_querying.html#conditions
raw code: ...where("orders_count = ? AND locked = ?", params[:orders], false)
Example Code: ...where(["(a= ? and b= ?) Or (a=? and b=?)", 1, true, 2, false])

Counting cascaded distincts in RavenDB

I'm facing an index problem for which I can't see a solution yet.
I have the following document structure per board:
{
"Name": "Test Board",
...
"Settings": {
"Admins": [ "USER1", "USER2" ],
"Members": [ "USER3", "USER4", "USER5" ]
...
},
...
"CreatedBy": "USER1",
"CreatedOn": "2014-09-26T18:14:20.0858945"
...
}
Now I'd like to be able to retrieve the count of all users which are somewhere registered in a board. Of course this should not only count the number of user occurences but rather count the number of distinct users. One user can be member of multiple boards.
This operation should perform as fast as possible since it is displayed in a global statistics dashboard visible on each page. Therefor I chose to try it with an index instead of retrieving all boards and their users and do the work on client side.
Trying to achieve this by using a Map/Reduce index:
Map = boards => from board in boards
select new
{
Aggregation = "ALL",
Users = new object[]
{
board.CreatedBy,
board.Settings.Admins,
board.Settings.Members
},
NumberOfUsers = 1
};
Reduce = results => from res in results
group res by new
{
res.Aggregation
}
into g
select new
{
g.Key.Aggregation,
Users = g.Select(x => x.Users),
NumberOfUsers = g.Sum(x => x.Users.Length)
};
Obviously this results in a wrong count. I don't have any experience with Reduce yet so I appreciate any tip! The solution will be probably pretty easy...
What would be the best way to globally distinct CreatedBy, Admins and Members of all documents and return the count?
Use an index like this:
from board in docs.Boards
select new
{
Users = board.Settings.Admins.Count + board.Settings.Members.Count + 1 /* created by */
}
from r in results
group r by "all" into g
select new
{
Users = g.Sum(x=>x.Users)
}
The best I could come up so far is:
Map = boards => from board in boards
select new
{
Users = new object[]
{
board.CreatedBy,
board.Settings.Admins,
board.Settings.Members
}
};
Reduce = results => from r in results
group r by "all" into g
select new
{
Users = g.SelectMany(x => x.Users)
};
And then query for the distinct user count:
var allUsersQuery = _documentSession.Query<AllUsersIndex.Result, AllUsersIndex>();
return allUsersQuery.Any() ? allUsersQuery.First().Users.Distinct().Count() : 0;
At least the query only returns a list of all usernames on all boards instead of bigger object trees. But the uniqueness still has to be done client-side.
If there is any better way please let me know. It would be beautiful to have only one integer returned from the server...
Then use this:
from board in docs.Boards
from user in board.Settings.Admins.Concat(board.Settings.Members).Concat(new[]{board.CreatedBy})
select new
{
User = user,
Count = 1
}
from r in results
group r by r.User into g
select new
{
User = g.Key,
Count = g.Sum(x=>x.Count)
}
I'm not really happy about the fanout, but this will give you all the discint users and the number of times they appear.
If you want just the number of distinct users, just get the total results from the index.

MongoDB: How retrieve data that is newly constructed instead of original documents in the collection?

I have a collection in which documents are all in this format:
{"user_id": ObjectId, "book_id": ObjectId}
It represents the relationship between user and book, which is also one-to-many, that means, a user can have more than one books.
Now I got three book_id, for example:
["507f191e810c19729de860ea", "507f191e810c19729de345ez", "507f191e810c19729de860efr"]
I want to query out the users who have these three books, because the result I want is not the document in this collection, but a newly constructed array of user_id, it seems complicated and I have no idea about how to make the query, please help me.
NOTE:
The reason why I didn't use the structure like:
{"user_id": ObjectId, "book_ids": [ObjectId, ...]}
is because in my system, books increase frequently and have no limit in amount, in other words, user may read thousands of books, so I think it's better to use the traditional way to store it.
This question is not restricted by MongoDB, you can answer it in relational database thoughts.
Using a regular find you cannot get back all user_id fields who own all the book_id's because you normalized your collection (flattened it).
You can do it, if you use aggregation framework:
db.collection.aggregate([
{
$match: {
book_id: {
$in: ["507f191e810c19729de860ea",
"507f191e810c19729de345ez",
"507f191e810c19729de860efr" ]
}
}
},
{
$group: {
_id: "$user_id",
count: { $sum: 1 }
}
},
{
$match: {
count: 3
}
},
{
$group: {
_id: null,
users: { $addToSet: "$_id" }
}
}
]);
What this does is filters through the pipeline only for documents which match one of the three book_id values, then it groups by user_id and counts how many matches that user got. If they got three they pass to the next pipeline operation which groups them into an array of user_ids. This solution assumes that each 'user_id,book_id' record can only appear once in the original collection.