Strapi sum values for a certain field - strapi

i'm trying to build an api for expenses notes with strapi.
I have trips and for each trip multiple expenses. (relation one to many).
I would like, when I go to /trips it will give me also the sum of all expenses for that trip. (each expense will have the proper amount)
I would need the sumField only in response and not on the model of the api (so i cannot modify it).
I Am using postrgres.
Definetelly i have to modify the controller find and find one but I don't know how make the sum.
Also if it is possible to have it querable from graphql.
Any help?

Exactly you will have to customize your API to add a new route and controller (to keep the current default API stuff) that will return what you need.
First you will have to create a route and a controller in the API you want. Trip in you case.
There is a doc here for an API named hello - replace hello by post. https://strapi.io/documentation/3.0.0-beta.x/guides/controllers.html#custom-controllers
And then in your controller, you will have something like this:
const { sanitizeEntity } = require('strapi-utils');
module.exports = {
async tripsWithSum (ctx) {
let entities;
if (ctx.query._q) {
entities = await strapi.services.trip.search(ctx.query);
} else {
entities = await strapi.services.trip.find(ctx.query);
}
entities = entities.map(entity => sanitizeEntity(entity, { model: Trip }));
entities = entities.map(entry => {
entry = Object.assign(entry, {
sumField: entry.expenses.length
});
});
return entities;
}
};

Thank you I will try. what if expenses is a relation field? Trips will have many expenses.

Related

Strapi v4 relations population

Hi I’m migration from strapi v3 to v4. I’m stuck for quite sometime regarding population of relations in v4.
BEHAVIOUR IN V3
Previously in v3 if I queried a service, it populated uptill the 2nd level by default if I’m not wrong, and in the second level if returned foreign keys from the further nested tables/relations respectively.
Example case I have following relations:
activity → cities → province , [images]
Querying activity like this in code:
const activity = await strapi.services.activity.findOne({ id });
would return activity → cities → { provinceforeignkey , images }
e.g. sample response
{
id: activity_id,
cities: [
id,
province: id_of_province,
images: [
// IMAGES DETAILED RESPONSE
]
]
}
BEHAVIOUR IN V4
I’m not able to get the desired response as above either by direct querying:
const activity = await strapi
.service("api::activity.activity")
.findOne(id,populate: ["cities"]);
Or by using entityService:
await strapi.entityService.findOne(
"api::activity.activity",
id,
populate: ["cities"]
);
I know we can use populate field to populate the desired relation, but on second level e.g. province case inside cities I need the id of province not the entire object population.
This is really important to us as we’ve tonnes of custom apis and custom code already implemented in v3 as per the following approach, otherwise we would have to go and change each case specifically in frontend and backend.
Can anyone guide me on this?
the entityService and db.query accept fields parameter that is undocumented but may work? However, what i would recommend is doing your own normalize function like:
let activities = await strapi.db.query('api::activity.activity')
.findOne({where: { id }, populate: { cities: { populate: ['state'] } } );
return normalizeManyActivities(activities)
and
const normalizeActivity = (activity) =>
({...activity,
cities: activity.cities.map(city =>
({...city, state: city.state.id })
})
);
const normalizeManyActivities = (activities) =>
activities.map(activity => normalizeActivity(activity));
and the second approach is to use middleware's witch you can take reference from here:
https://www.youtube.com/watch?v=YIbhKm1o0fE

Strapi change one collection and apply change to other one

Lets say i create an entry where i can select two collections like this
now , how to detec when someone changed first collection and then apply some filter to data in second collection ?
not sure if you're still looking for the answer but your question ranked high on my search so here's an answer for future visitors.
Say you add a post entry for your Posts collection. In the ./api/post/models/post.js you can create a hook like this
'use strict';
module.exports = {
lifecycles: {
async afterCreate(result, data) {
const id = result.streakID;
const streak = strapi.services.streaks.findOne({ id });
strapi.services.streaks.update({ id }, { counter: streak.counter++ });
},
},
};
My source
Best regards
EDIT: the hook runs on Post creation and accesses the Streak model by way of strapi.services.streaks. To be clear.

custom strapi api - query model involving relation

In strapi I have two collections, products & categories related to each other, i.e. a product is related to many categories.
My question is: how do I form a query like get me products of category 'keys'
The controller of this specific route is sth like:
module.exports = {
async index(ctx) {
const keys = await strapi.services.product.find({ category[0].title: 'keys' });
return keys
}
}
..but obviously this produces an error
Hi #Dimitris this should work in your case.
async index(ctx) {
const products = await strapi.services['product'].find({ 'categories.title': 'keys' });
return products
}

How can I link 2 existing models in my laravel code?

I have two models customer and orders. They are already fecthed separately
$customers = customer::all();
$orders = orders::all();
customerID=1 has orderID : 1, 2,4 customerID=2 has orderID : 3,5,9
They are related (hasMany, belongsTo) but the problem is inside my for a certain reason they are separated but I want to send them as response in API using toJson or ToArray as one data having the orders nested to their correct customers.
How can I achieve that linking to have at the end one variable $customersWithOrders that should be transformed to JSON ?
I am using laravel 5.5
I don't know what the context is. Defining relationships as other answers mentioned is a good solution.
In addition, I recently read a pretty good article about this specific scenario.
So you can also do something like this, if you have already retrieved customers and orders:
$customers = Customer::all();
$orders = Order::all();
return $customers->each(function ($customers) use ($orders) {
$customer->setRelation('orders', $orders->where('customer_id', $customer->id));
});
If you already have a relation you just use it. For example, in model Customer.php:
public function orders()
{
return $this->hasMany(Order::class);
}
Then you'd get customer orders by calling $customer->orders
If you already have defined relations, you can simply fetch data with eager loading
// in customer model
public function orders()
{
return $this->hasMany(orders::class, 'orderID');
}
// in controller
$customersWithOrders = customer::with('orders')->get();
return response()->json(['customersWithOrders' => $customersWithOrders]);
// in js
for (let customer in response.customersWithOrders){
let orders = customer.orders
}

Filtering eager-loaded data in Laravel 4

I have the following setup:
Clubs offer Activities, which are of a particular Type, so 3 models with relationships:
Club:
function activities()
{
return $this->hasMany('Activity');
}
Activity:
function club()
{
return $this->belongsTo('Club');
}
function activityType()
{
return $this->hasMany('ActivityType');
}
ActivityType:
function activities()
{
return $this->belongsToMany('Activity');
}
So for example Club Foo might have a single Activity called 'Triathlon' and that Activity has ActivityTypes 'Swimming', 'Running', and 'Cycling'.
This is all fair enough but I need to show a list of ActivityTypes on the Club page - basically just a list. So I need to get the ActivityTypes of all the related Activities.
I can do that like so from a controller method that receives an instance of the Club model:
$data = $this->club->with(array('activities', 'activities.activityTypes'))->find($club->id)
That gets me an object with all the related Activities along with the ActivityTypes related to them. Also fair enough. But I need to apply some more filtering. An Activity might not be in the right status (it could be in the DB as a draft entry or expired), so I need to be able to only get the ActivityTypes of the Activities that are live and in the future.
At this point I'm lost... does anybody have any suggestions for handling this use case?
Thanks
To filter, you can use where() as in the fluent DB queries:
$data = Club::with(array('activities' => function($query)
{
$query->where('activity_start', '>', DB::raw('current_time'));
}))->activityType()->get();
The example which served as inspiration for this is in the laravel docs, check the end of this section: http://laravel.com/docs/eloquent#eager-loading
(the code's not tested, and I've taken some liberties with the property names! :) )
I think if you first constraint your relationship of activities, the activity types related to them will be automatically constrained as well.
So what I would do is
function activities()
{
return $this->belongsToMany('Activity')->where('status', '=', 'active');
}
and then your
$data = $this->club->with(array('activities', 'activities.activityTypes'))->find($club->id)`
query will be working as you would expect.

Resources