I am creating a game and using PayloadCMS to manage content and data for the game. One part of this is various "factions" that players and NPCs can be a part of.
Part of what I'd like to manage in PayloadCMS is data around the relationships between factions. By doing this, each faction should be able to have a field that references a different faction. I thought a relationship field might work for this but that might not be the best solution and seems to currently be impossible.
When attempting to create a recursive relationship field, I get an error message as follows:
Field Faction Id has invalid relationship 'factions'., stack=InvalidFieldRelationship: Field Faction Id has invalid relationship 'factions'.
I suppose that this makes sense because "factions" is not yet defined as a collection when this field is defined.
const fields: Field[] = [
{
name: 'id',
type: 'text',
required: true,
unique: true,
label: 'Should be underscored, used as a reference in attrs, npcs and quests.'
},
{
name: 'name',
type: 'text',
required: true,
label: 'This is what the player sees.'
},
{
name: 'relationships',
type: 'array',
fields: [{
name: 'factionId',
type: 'relationship',
relationTo: 'factions',
maxDepth: 0,
}, {
name: 'reputation',
type: 'number',
min: 0,
max: 100,
defaultValue: 50,
}],
label: 'Relationships with other factions',
hooks: {
afterRead: [({ value: relationships }) => {
// Transform array of relationships into an object where the factionId is key:
return relationships.reduce((acc: Record<string, number>, { factionId, reputation }) => ({
...acc,
[factionId]: reputation,
}), {});
}]
}
}
];I imagine there may be a way for me to write some kind of custom field that allows for this, or have a separate collection to describe the relationships between factions, or hardcode some of it (e.g. maintain an array of factionIds that duplicates the data in the CMS though that's not ideal).
Anyway, is it possible to do this with a "relationships" field or a different built-in type?
As an aside, I found a workaround that minimizes hardcoding anything while working for my use case. Still curious about this possibility but it's far from urgent. Thanks
I am running into an error with my workaround
Collection "factions" > Field "factionRelationships" > "value" does not match any of the allowed types
import { FACTION_NAMES, REPUTATIONS } from "lib/Factions";
import { Field } from "payload/dist/fields/config/types";
// The CMS expects string values for its select options:
const FACTION_REPUTATIONS = Object.entries(REPUTATIONS).map(([key, value]) => ({ label: key, value: String(value) }));
// Ensure that the faction ID used in each document or for factionRelationships exists in code:
const validateFactionId = (value: string) => {
if (!FACTION_NAMES.includes(value as typeof FACTION_NAMES[number])) {
return `Invalid faction id: ${value}. See Factions.ts for a list of valid values.`;
}
return true;
}
const fields: Field[] = [
{
name: 'id',
type: 'text',
required: true,
unique: true,
validate: validateFactionId
},
{
name: 'name',
type: 'text',
required: true,
unique: true,
label: 'What the player sees.'
},
{
name: 'factionRelationships',
type: 'array',
fields: [{
name: 'factionId',
type: 'select',
options: [...FACTION_NAMES],
required: true,
}, {
name: 'reputation',
type: 'select',
options: [...FACTION_REPUTATIONS],
defaultValue: REPUTATIONS.AMBIVALENCE,
hooks: {
// The game expects a number here:
afterRead: [({ value }) => {
return Number(value);
}]
},
validate: validateFactionId
}]
}
];
export const factions = {
admin: {
useAsTitle: 'name',
group: 'Narrative',
},
slug: 'factions',
fields,
};Oof, okay, the issue above was that
defaultValuefor the reputation field needed to also be a string.
There should be no issue with recursive relationships, as we've done this before. An example of that is in the pages collection of the public demo:
https://github.com/payloadcms/public-demo/blob/master/src/collections/Pages/index.ts#L145Thank you for the example
@967118574445547650! Could the issue have been with the hook I defined rather than the recursiveness?
The error you saw specifically comes from us validation slugs on relationships, so it's odd that you were seeing it.
Agreed. I did see the same error in some spots where I had a
relationshiptype with
defaultValue: []-- the defaultValue was not only unnecessary but caused an error. But that wasn't the case here. Possible that I had an incorrect slug at one point, though. I did have some copy and paste errors along those lines.
Star
Discord
online
Get dedicated engineering support directly from the Payload team.