I have a Strapi server.
It has a Customer entity and a Children entity.
Customers have many children, and children have only one customer.
I try to customize the customer-create API to create a Customer and children and connect them to the customer on the same request.
I searched this topic extensively in the past week, but nothing has worked.
I allowed all of the permissions.
I logged the responses.
I get this error:
[2025-02-12 15:02:24.244] error: Document with id "b2vpvz81yx4v1ojlf0jxewib", locale "null" not found
on this line of code (I tried create()
as well, not just update()
):
await strapi.documents("api::customer.customer").update({
documentId: customer.documentId,
data: {
children: {
connect: childrenToAdd.map((child) => child.documentId),
},
},
});
the error is on the children documentID.
But the creation of the children (that happened few lines above) wasn't throwing errors and it returns the ID that is not found.
my current variation of the code is:
"use strict";
import { factories } from "@strapi/strapi";
import { Core } from "@strapi/strapi";
export default factories.createCoreController(
"api::customer.customer",
({ strapi }: { strapi: Core.Strapi }) => ({
async create(ctx) {
try {
const requestBody = ctx.request.body;
const { children, ...customerData } = requestBody.data;
console.log({ customerData, children });
// Create the customer first
const customer = await strapi.service("api::customer.customer").create({
data: customerData,
});
const publishedCustomer = await strapi
.documents("api::customer.customer")
.publish({
documentId: customer.documentId,
});
console.log({ publishedCustomer });
// If children exist, create them and associate them with the customer
if (children && Array.isArray(children)) {
const childrenToAddPromises = children.map(async (child) => {
const childrenToPublish = await strapi.db
.query("api::children.children")
.create({
data: child,
});
const publishedChildren = await strapi
.documents("api::children.children")
.publish({
documentId: childrenToPublish.documentId,
});
return publishedChildren;
});
const childrenToAdd = await Promise.all(childrenToAddPromises);
await strapi.documents("api::customer.customer").update({
documentId: customer.documentId,
data: {
children: {
connect: childrenToAdd.map((child) => child.documentId),
},
},
});
}
return customer;
} catch (error) {
ctx.throw(400, error.message);
}
},
})
);
Does anyone managed to create and connect entities in the same call in Strapi?
I use
"@strapi/plugin-cloud": "5.9.0",
"@strapi/plugin-documentation": "^5.9.0",
"@strapi/plugin-users-permissions": "5.9.0",
"@strapi/strapi": "5.9.0",
I test the server using the generated swagger from plugin-documentation.
TL;DR - How to create entities and relations in Strapi - solved!
Customer Controller
/src/api/customer/controllers/customer.ts
"use strict";
import { factories } from "@strapi/strapi";
import { Core } from "@strapi/strapi";
export default factories.createCoreController(
"api::customer.customer",
({ strapi }: { strapi: Core.Strapi }) => ({
async create(ctx) {
try {
const requestBody = ctx.request.body;
const { children, ...customerData } = requestBody.data;
// Create the customer first
const customer = await strapi.service("api::customer.customer").create({
data: customerData,
});
let addedChildren;
// If children exist, create them and associate them with the customer
if (children && Array.isArray(children)) {
const childrenToAddPromises = children.map((child) => {
return strapi.service("api::children.children").create({
data: {
customer_id: customer.id,
...child,
},
});
});
addedChildren = await Promise.all(childrenToAddPromises);
await strapi.documents("api::customer.customer").update({
documentId: customer.documentId,
data: {
children: {
connect: addedChildren.map((child) => child.documentId),
},
},
});
}
return { ...customer, children: addedChildren };
} catch (error) {
ctx.throw(400, error.message);
}
},
})
);
Keynotes:
update()
throw the error: document with id not found
even tho the query did return documented.
This was the code: const childrenToAddPromises = children.map(async (child) => {
const childrenToPublish = await strapi.db
.query("api::children.children")
.create({
data: child,
});
const publishedChildren = await strapi
.documents("api::children.children")
.publish({
documentId: childrenToPublish.documentId,
});
return publishedChildren;
});
const childrenToAdd = await Promise.all(childrenToAddPromises);
console.log({ childrenToAdd });
await strapi.documents("api::customer.customer").update({
documentId: customer.documentId,
data: {
children: {
connect: childrenToAdd.map((child) => child.documentId),
},
},
});
data
field and the appropriate data. In my initial attempts, I incorrectly created the children by directly passing the child object to the create function of the service engine. The error message I received pointed to a schema validation issue for one of the children (card_number must be at least 9 characters), making it quite challenging to comprehend the underlying problem.Right
strapi.service("api::children.children").create({
data: { //<-- this field
customer_id: customer.id,
...child,
},
});
Wrong
strapi.service("api::children.children").create({
customer_id: customer.id,
...child,
});
I'm unclear about its meaning: perhaps I shouldn't utilize the connect API on documents produced via a bulk operation. Or is the API not being used on the operation itself? An example code would have been helpful. It appears that minimizing reliance on the DB query engine is advised. When I moved to the service engine, the relation and the entity were created.