custom strapi api - query model involving relation - strapi

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
}

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

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
}

Strapi sum values for a certain field

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.

Storefront API: querying for variable parameters?

The Shopify Storefront API examples show an App.js view listing all products on one page. In these examples, products are added to the cart from this index page, and there is no product detail page. Unlike the examples, I want to click through to a product details page from an index of products.
The products index was easy. But I'm having alot of trouble understanding how to create a page per product.
Seems I can't use a graphql query with a variable on Shopify Storefront. For example, this fails:
query myQuery($id: ID!) {
Product(id: $id) {
id
title
}
}
I'm using nuxt and vue-apollo to build the frontend.
Any pointers appreciated.
The query you've provided is missing the actual variable value that you're querying.
The body of the HTTP request to the GraphQL endpoint should look like this:
query:"query myQuery($id: ID!) {
Product(id: $id) {
id
title
}
}"
variables:{id: "ce03707f-971e-4c64-853c-06a8c2e21448"}
Edit: Vue specific example:
// Apollo-specific options
apollo: {
// Query with parameters
ping: {
// gql query
query: gql`query PingMessage($message: String!) {
ping(message: $message)
}`,
// Static parameters
variables: {
message: 'Meow',
},
},
},
from: https://akryum.github.io/vue-apollo/guide/apollo/queries.html#query-with-parameters

Laravel Collection filter into Parent Data

I have created map table for relation between Products & Product Categories. I want to get Product object from collection using below code.
return $collection->products->product_categories()->get()->filter(function($item) use ($itemIds)
{
if(isset($item->pivot->parent->id))
{
return $item->pivot->parent;
}
});
If I dump and die parent then I can see Product object but when I try to return Product it shows Category data.
You're almost there. You just need to return the product data from the categories. Assuming your code works, you just have to map the collection to return the parent from the pivot.
return $collection->products->product_categories()->get()->filter(function($item) use ($itemIds)
{
if(isset($item->pivot->parent->id))
{
return $item->pivot->parent;
}
})->map(function($item){
return $item->pivot->parent;
});

Resources