I have a table posts as follows:
+------+--------+-----------+---------+------------+
| id | title | category | visits | content |
+------+--------+-----------+---------+------------+
| 1 | aaa | 1 | 44 | Text co... |
| 2 | bbb | 1 | 63 | Text co... |
| 3 | ccc | 2 | 42 | Text co... |
| 4 | ddd | 2 | 65 | Text co... |
| 5 | eee | 2 | 73 | Text co... |
| 6 | fff | 3 | 57 | Text co... |
| 7 | ggg | 3 | 79 | Text co... |
| 8 | hhh | 3 | 62 | Text co... |
| 9 | iii | 2 | 46 | Text co... |
| 10 | jjj | 4 | 64 | Text co... |
| 11 | kkk | 4 | 76 | Text co... |
+------+--------+-----------+---------+------------+
I am trying to obtain the most visited posts in each category along with their data like id, title and content.
With the below query I am able to obtain an entry for each category
db.posts.aggregate([
{"$group": {
"_id": "$category",
"count": {"$sum": 1},
"max-visits": { $max: "$visits" }
}}
]);
I am able to obtain the category along with maximum of visitors of that category and the no of posts in it. But I also require id, title and content of the post that has maximum visits.
Expected output:
+------+--------+----------------+---------+------------+
| id | title | category(_id) | visits | content |
+------+--------+----------------+---------+------------+
| 1 | bbb | 1 | 63 | Text co... |
| 2 | eee | 2 | 73 | Text co... |
| 3 | ggg | 3 | 79 | Text co... |
| 4 | kkk | 4 | 76 | Text co... |
+------+--------+----------------+---------+------------+
Actual output:
+-----------------+--------+-------------+
| category(_id) | count | max-visits |
+-----------------+--------+-------------+
| 1 | 2 | 63 |
| 2 | 4 | 73 |
| 3 | 3 | 79 |
| 4 | 2 | 76 |
+-----------------+--------+-------------+
You should $sort before $group then you can easily get $first document's fields.
db.posts.aggregate([
{"$sort": { category: 1, visits: -1 }},
{"$group": {
"_id": "$category",
"count": {"$sum": 1},
"max-visits": { $max: "$visits" },
"doc_id": { $first: "$_id" },
"title": { $first: "$title" },
"content": { $first: "$content" }
}}
]);
Related
I have a table like this in database
+---+-------------+--------------+
|id | service_name| doc_id |org_id|
+---+-------------+--------------+
| 1 | new service | 12 | 119 |
| | | | |
| 2 | new service | 24 | 119 |
| | | | |
| 3 | old service | 13 | 118 |
| | | | |
| 4 | old service | 14 | 118 |
| | | | |
| 5 | new service | 20 | 119 |
+---+-------------+--------------+
I want to group all the doc_id's according to service_name column
I have tried using
IN my controller
$where_person['org_id'] = $this->post('org_id');
$result_insert = $this->$model_name->fetch_doctor_services($where_person);
In my Model
function fetch_doctor_services($where){
$this->db->select('service_name,doc_id')->from('services');
$this->db->group_by('service_name');
$this->db->where($where);
return $this->db->get()->result();
}
But it does not output data as i desire, by grouping by service_name and all the doc_id's according to that service_name.
where am i going wrong here?
Currently my output is like this.
{ "data":
[ { "service_name": "new service", "doc_id": "12" },
{
"service_name": "old service", "doc_id": "13" }
]
}
You need to use GROUP_CONCAT. See below code on how to use it
$this->db->select('service_name, GROUP_CONCAT( doc_id) ')->from('services');
$this->db->group_by('service_name');
$this->db->where($where);
return $this->db->get()->result();
I have a table called places_log. The schema for places logs is as follows
{
'type': {
'type': 'string',
'required': True,
'allowed': ['in', 'out']
},
'fence_name': {
'type': 'string',
'required': True
},
'time': {
'type': 'datetime',
'required': True
}
}
When a query to get all the documents of this table sorted by fence name and time is made, say the output is as follows
+------------+---------+-----------+
| fence_name | type | time |
+------------+---------+-----------+
| abc | in | 08:30 |
| abc | in | 08:32 |
| abc | out | 09:45 |
| abc | in | 15:18 |
| abc | out | 16:20 |
| abc | out | 16:25 |
| lmn | in | 12:30 |
| pqr | in | 12:40 |
| pqr | out | 13:52 |
| pqr | out | 13:58 |
| xyz | out | 19:43 |
| xyz | out | 19:45 |
+-------------+--------+-----------+
I want a query which will return the following result. For each fence, when there are simultaneous ins, I want the latest in and when there are simultaneous outs, I want the latest out.
+------------+---------+-----------+
| fence_name | type | time |
+------------+---------+-----------+
| abc | in | 08:32 |
| abc | out | 09:45 |
| abc | in | 15:18 |
| abc | out | 16:25 |
| lmn | in | 12:30 |
| pqr | in | 12:40 |
| pqr | out | 13:58 |
| xyz | out | 19:45 |
+-------------+--------+-----------+
Basically there is a feature where the user can create multiple fences on the map we will store the times when the user's vehicle enters or exits the fence. Due to some edge cases, we are getting multiple 'in' events simultaneously without an 'out' event which is not possible. So I am trying to come up with a query where I can only take the last 'in' event (when there are simultaneous ins) and take that time as the time when the vehicle entered the fence.
But the vehicle can enter and exit a fence multiple times. So I have to get all those ins and outs also
Doing an aggregation using group and last will not consider ins and outs which are not simultaneous, for the following aggregation
[
{ "$sort": { "fence_name": 1, "time": 1 } },
{
'$group': {
"_id": {
"fence_name": "$fence_name",
"type": "$type"
},
"time": {
"$last": "$time"
}
}
}
]
We will get a something like this
+------------+---------+-----------+
| fence_name | type | time |
+------------+---------+-----------+
| abc | in | 15:18 |
| abc | out | 16:25 |
| lmn | in | 12:30 |
| pqr | in | 12:40 |
| pqr | out | 13:58 |
| xyz | out | 19:45 |
+-------------+--------+-----------+
Here, I don't get the second time the vehicle entered and exited the fence 'abc'
I want to get multiple ins and outs which are not simultaneous.
And even better if I can get something like this
+------------+---------+-----------+
| fence_name | in | out |
+------------+---------+-----------+
| abc | 08:32 | 09:45 |
| abc | 15:18 | 16:25 |
| lmn | 12:30 | null |
| pqr | 12:40 | 13:58 |
| xyz | null | 19:45 |
+-------------+--------+-----------+
I want to find for each row(where B = C = D = 1), the max of A among its previous rows(where B = C = D = 1) excluding its row after its ordered in chronological order.
Data in table looks like this:
+-------+-----+-----+-----+------+------+
|Grp id | B | C | D | A | time |
+-------+---- +-----+-----+------+------+
| 111 | 1 | 0 | 0 | 52 | t |
| 111 | 1 | 1 | 1 | 33 | t+1 |
| 111 | 0 | 1 | 0 | 34 | t+2 |
| 111 | 1 | 1 | 1 | 22 | t+3 |
| 111 | 0 | 0 | 0 | 12 | t+4 |
| 222 | 1 | 1 | 1 | 16 | t |
| 222 | 1 | 0 | 0 | 18 | t2+1 |
| 222 | 1 | 1 | 0 | 13 | t2+2 |
| 222 | 1 | 1 | 1 | 12 | t2+3 |
| 222 | 1 | 1 | 1 | 09 | t2+4 |
| 222 | 1 | 1 | 1 | 22 | t2+5 |
| 222 | 1 | 1 | 1 | 19 | t2+6 |
+-------+-----+-----+-----+------+------+
Above table is resultant of below query. Its obtained after left joins as below. Joins are necessary according to my project requirement.
SELECT Grp id, B, C, D, A, time, xxx
FROM "DCR" dcr
LEFT JOIN "DCM" dcm ON "Id" = dcm."DCRID"
LEFT JOIN "DC" dc ON dc."Id" = dcm."DCID"
ORDER BY dcr."time"
Result column needs to be evaluated based on formula I mentioned above. It needs to be calculated in same pass as we need to consider only its previous rows. Above xxx needs to be replaced by a subquery/statement to obtain the result.
And the result table should look like this:
+-------+-----+-----+-----+------+------+------+
|Grp id | B | C | D | A | time |Result|
+-------+---- +-----+-----+------+------+------+
| 111 | 1 | 0 | 0 | 52 | t | - |
| 111 | 1 | 1 | 1 | 33 | t+1 | - |
| 111 | 1 | 1 | 1 | 34 | t+2 | 33 |
| 111 | 1 | 1 | 1 | 22 | t+3 | 34 |
| 111 | 0 | 0 | 0 | 12 | t+4 | - |
| 222 | 1 | 1 | 1 | 16 | t | - |
| 222 | 1 | 0 | 0 | 18 | t2+1 | - |
| 222 | 1 | 1 | 0 | 13 | t2+2 | - |
| 222 | 1 | 1 | 1 | 12 | t2+3 | 16 |
| 222 | 1 | 1 | 1 | 09 | t2+4 | 16 |
| 222 | 1 | 1 | 1 | 22 | t2+5 | 16 |
| 222 | 1 | 1 | 1 | 19 | t2+6 | 22 |
+-------+-----+-----+-----+------+------+------+
The column could be computed with a window function:
CASE WHEN b = 1 AND c = 1 AND d = 1
THEN max(a) FILTER (WHERE b = 1 AND c = 1 AND d = 1)
OVER (PARTITION BY "grp id"
ORDER BY time
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING)
ELSE NULL
END
I didn't test it.
I have the following PostgreSQL table structure, which gathers temperature records for every second:
+----+--------+-------------------------------+---------+
| id | value | date | station |
+----+--------+-------------------------------+---------+
| 1 | 0 | 2017-08-22 14:01:09.314625+02 | 1 |
| 2 | 0 | 2017-08-22 14:01:09.347758+02 | 1 |
| 3 | 25.187 | 2017-08-22 14:01:10.315413+02 | 1 |
| 4 | 24.937 | 2017-08-22 14:01:10.322528+02 | 1 |
| 5 | 25.187 | 2017-08-22 14:01:11.347271+02 | 1 |
| 6 | 24.937 | 2017-08-22 14:01:11.355005+02 | 1 |
| 18 | 24.875 | 2017-08-22 14:01:17.35265+02 | 1 |
| 19 | 25.187 | 2017-08-22 14:01:18.34673+02 | 1 |
| 20 | 24.875 | 2017-08-22 14:01:18.355082+02 | 1 |
| 21 | 25.187 | 2017-08-22 14:01:19.361491+02 | 1 |
| 22 | 24.875 | 2017-08-22 14:01:19.371154+02 | 1 |
| 23 | 25.187 | 2017-08-22 14:01:20.354576+02 | 1 |
| 30 | 24.937 | 2017-08-22 14:01:23.372612+02 | 1 |
| 31 | 0 | 2017-08-22 15:58:53.576238+02 | 1 |
| 32 | 0 | 2017-08-22 15:58:53.590872+02 | 1 |
| 33 | 26.625 | 2017-08-22 15:58:54.59986+02 | 1 |
| 38 | 26.375 | 2017-08-22 15:58:56.593205+02 | 1 |
| 39 | 0 | 2017-08-21 15:59:40.181317+02 | 1 |
| 40 | 0 | 2017-08-21 15:59:40.190221+02 | 1 |
| 41 | 26.562 | 2017-08-21 15:59:41.182622+02 | 1 |
| 42 | 26.375 | 2017-08-21 15:59:41.18905+02 | 1 |
+----+--------+-------------------------------+---------+
I want now to retrieve the maximum value for every hour, along with the data associated to that entry (id, date). As such, I tried the following:
select max(value) as m, (date_trunc('hour', date)) as d
from temperature
where station='1'
group by (date_trunc('hour', date));
Which works fine (fiddle), but I only get the columns m and d as a result. If I now try to add the date or id columns to the SELECT statement, I get the usual column "temperature.id" must appear in the GROUP BY clause or be used in an aggregate function error.
I have already tried approaches such as the ones described here, unfortunately to no avail, as for instance I seem to be unable to perform a join on the date_trunc-generated columns.
The result I am aiming for is this:
+----+--------+-------------------------------+---------+
| id | value | date | station |
+----+--------+-------------------------------+---------+
| 3 | 25.187 | 2017-08-22 14:01:10.315413+02 | 1 |
| 33 | 26.625 | 2017-08-22 15:58:54.59986+02 | 1 |
| 41 | 26.562 | 2017-08-21 15:59:41.182622+02 | 1 |
+----+--------+-------------------------------+---------+
It does not matter which record was retrieved in case two or more entries have the same value.
distinct on:
select distinct on (date_trunc('hour', date)) *
from temperature
where station = '1'
order by date_trunc('hour', date), value desc
Fiddle
I have Document with field: _id, title, one, two, positionOne, positionTwo
For example:
_id | title | one | two | positionOne | positionTwo
1 | aaa | 12,2| 10 | |
2 | bbb | 3,2 | 12,2| |
3 | ccc | 12,6| 2 | |
4 | ddd | 3 | 4 | |
5 | eee | 5,5 | 5 | |
And I would like receive:
_id | title | one | two | positionOne | positionTwo
1 | aaa | 12,2| 10 | 2 | 3
2 | bbb | 3 | 12,2| 4 | 2
3 | ccc | 12,6| 2 | 1 | 5
4 | ddd | 3 | 4 | 4 | 4
5 | eee | 5,5 | 15 | 3 | 1
I would like add positions from max to min.
Is this possible only with Mongo queries to db?