Strapi change one collection and apply change to other one - strapi

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.

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 : populate from a relation

In the example
on the site
Strapi Docs
To populate specific relations, one or several levels deep, use the LHS bracket notation for fields names in combination with the populate parameter. The qs library (opens new window)is helpful to build complex URLs:
const qs = require('qs');
const query = qs.stringify({
populate: {
author: {
populate: ['company'],
}
}
}, {
encodeValuesOnly: true,
});
await request(`/api/articles?${query}`);
// GET /api/articles?populate[author][populate][0]=company
How to fill relationships, two three or more several levels deep?
In my example, I tried
/api/regions?populate[cities][populate][0]=holding?spopulate[companies][populate][0]=holdings
The answer to this question was posted here. Make sure you're using Strapi v4 and simply install the plugin to the Strapi server.

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.

apollo-link-state defaults derived from query data?

Note: This is a followup question to my previous question about Apollo GraphQl Storing derived data
I'm using apollo-link-state to store data that's derived from query data. In this example the query data from the db includes some (x,y) points on a graph and the derived data is slope, moving average, acceleration etc.
My React graphing components need different combinations of original and derived data. Some need only the original.
I need derived data to be calculated only once and only when I query for it.
The example on the Apollo site seems to imply needing to trigger a mutation first but that seems wrong to me since each component that uses this derived data needs to trigger a mutation first to make sure it's initialized. I don't want to do a query and a mutation everywhere I need data.
So my question is: Can/should I use query resolvers in apollo-link-state or is there some better way of thinking about this?
UPDATE: I think their async example might be what I need but I need to work it through.
Figured it out. Don't know why this wasn't obvious to me to begin with but.... hindsight.
In the end, you just need to define your resolver to return something. The resolver can even make its own queries.
export const getProjectDerived = (_obj, { ProjectId }, { cache }, info) => {
const projQueryRes = cache.readQuery({
query: projQuery,
variables: {
ProjectId
}
})
const newObj = { ...something here... }
return newObj
}
Then just include it in the 'Query' section of the resolvers.
import { getProjectDerived } from './project'
const resolvers = {
Query: {
ProjectDerived: getProjectDerived
}
}
export default resolvers

Fetching multiple levels of objects with kendo ui datasource?

I'm very new to developing mobile applications with telerik appbuilder. There are some things I have a hard time to understand with fetching data from Everlive.
Lets consider a simple example. Lets say I have Blog Posts and Comments that belong to those Posts. And both Posts and Comments are made by Users.
In one view I want to present the Post with corresponding Comments and I also need the Username of the User who posted the Comment (Comment table only contains userId).
Both the Post and the Comments are easy to fetch since I have the id of the Post. But how do I fetch the corresponding user for each Comment?
The FriendsApp example does something very similar but it uses this line to get the user:
var user = $.grep(app.Users.users(), function (e) {
return e.Id === userId;
})[0];
This fetches all users and filters them client side? I guess this is okay if you have like 10 users. But what if you have a million users?
I am guessing that the FriendsApp uses this way of resolving the relations just for keeping the simplicity of the sample. Everlive offers a far more meaningful toolset for resolving relation fields called Expand. You can explore the REST API here:
http://docs.telerik.com/platform/backend-services/development/rest-api/relations/simple-expanding
or the JS SDK function here:
http://docs.telerik.com/platform/backend-services/development/javascript-sdk/relations/simple-expanding.
As the Friends app uses the Kendo UI data source component you can send an Expand header with the request. The following configuration of the data source will return the DisplayName of the user in each Activity/Comments entity:
var expandObject = {
"CreatedBy": {
"ReturnAs": "User",
"SingleField": "DisplayName"
}
};
var dataSource = new kendo.data.DataSource({
type: "everlive",
transport: {
typeName: 'Activities', // replace this with Comments
read: {
beforeSend: function (xhr) {
xhr.setRequestHeader("X-Everlive-Expand", JSON.stringify(expandObject))
},
}
},
schema: {
model: {
id: Everlive.idField
}
}
});
dataSource.fetch(function (data) {
console.log(data.items);
});
Same could be applied for resolving the comments for each Blog post. Given the Friends data schema you will need to use the External Relation resolver of the Everlive API. Note that it is available only in a GetById scenario, e.g. when retrieving an Activity by Id, you can resolve the Comments that point to this activity, which is generally very handy in master-detail views.

Resources