Updating a Smart Field created from a Many to Many relationship

My products and tags models have a many to many relationship through the productTags model.

product Model

    Products.belongsToMany(models.tags, {
      through: 'productTags',
      foreignKey: 'product_id',
      otherKey: 'tags_id',
      as: 'tags',
    });

tags Model

    Tags.belongsToMany(models.products, {
      through: 'productTags',
      foreignKey: 'tags_id',
      otherKey: 'product_id',
      as: 'products',
    });

productTags Model

    ProductTags.belongsTo(models.products, {
      foreignKey: {
        name: 'productIdKey',
        field: 'product_id',
      },
      as: 'product',
    });
    ProductTags.belongsTo(models.tags, {
      foreignKey: {
        name: 'tagsIdKey',
        field: 'tags_id',
      },
      as: 'tags',
    });

Expected behavior

When I create a Smart Field from a many to many relationship, I can in turn edit associations from the Edit record interface.

Actual behavior

The following code defines my Smart Fields in the /forest/products.js file

const tagTypeFields = getTagTypeFields()

collection('products', {
	actions: [],
	fields: [...tagTypeFields],
	segments: [],
});

function getTagTypeFields() {
	const tagTypes = getTagTypes()
	return tagTypes.map(tagType => {
		let tagTypeName = produtTagsMap[tagType]
		return {
			field: tagTypeName,
			type: 'String',
			get: (product) => displayTagName(product, tagType),
			set: async (product, tagName) => {
				const productBeforeUpdate = await models.products.findOne({ where: { id: product.id }});
				const updatedTag = await models.tags.findOne({ where: { name: tagName }});
				
				await productBeforeUpdate.addTag(updatedTag)

				return product
			}
		}
	})
}

Failure Logs

The line which runs await productBeforeUpdate.addTag(updatedTag) Executes the following SQL statement and immediately throws an error:

Executing (default): SELECT "product_id" AS "productId", "tags_id" AS "tagsId", "product_id" AS "productIdKey", "tags_id" AS "tagsIdKey", "product_id", "tags_id" FROM "public"."product_tags" AS "productTags" WHERE "productTags"."product_id" = '607' AND "productTags"."tags_id" IN ('145');
Unhandled rejection
AggregateError of:
    SequelizeBulkRecordError: notNull Violation: productTags.productId cannot be null,
    notNull Violation: productTags.tagsId cannot be null

Context

This is my package.json

{
  "name": "foxxbee-admin",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node ./server.js"
  },
  "dependencies": {
    "body-parser": "1.19.0",
    "chalk": "~1.1.3",
    "cookie-parser": "1.4.4",
    "cors": "2.8.5",
    "debug": "~4.0.1",
    "dotenv": "~6.1.0",
    "express": "~4.17.1",
    "express-jwt": "6.0.0",
    "forest-cli": "^2.3.5",
    "forest-express-sequelize": "^8.0.0",
    "morgan": "1.9.1",
    "pg": "~8.2.2",
    "require-all": "^3.0.0",
    "sequelize": "~5.15.1"
  }
}

Hi @cooki23,

A many-to-many relationship should be working and editable without creating a smart field. Can you give the details about why you are planning a smart field?

As I read the getTagTypeFields function, I understand it returns an array of fields definition. These fields definition are inserted the smart fields of the collection products.
About this code:

  • The getTagTypes() function is not defined. Is it synchronous?
  • Can you please try a version with only 1 tag type?
  • I do not understand why one smart field is created for each tag type. Please explain if relevant.

Also, to try to reproduce your case, can you please share a SQL script which allows to recreate the tables involded in the issue?

Regards

Hey @Sliman_Medini , I am planning a Smart field mainly to make it easier to use the UI. Instead of having to click on a product record → tags → add existing tag, I can just click on the record → edit → edit my smart field.

ex:

Another major reason is that I would like to see them in a column view like in the picture below

The getTagTypes() function is indeed synchronous, here is its definition:

function getTagTypes() {
	return Object.keys(produtTagsMap)
}

I tried a version with only one tag, I get the same Error:

AggregateError of:
    SequelizeBulkRecordError: notNull Violation: productTags.productId cannot be null,
    notNull Violation: productTags.tagsId cannot be null

Here is a dump from the three mentionned tables:

--
-- PostgreSQL database dump
--

-- Dumped from database version 14.0
-- Dumped by pg_dump version 14.0

SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;

SET default_tablespace = '';

SET default_table_access_method = heap;

--
-- Name: tags; Type: TABLE; Schema: public; Owner: camillefeghali
--

CREATE TABLE public.tags (
    id bigint NOT NULL,
    name character varying(255),
    tag_type integer,
    priority integer
);


ALTER TABLE public.tags OWNER TO camillefeghali;

--
-- Name: tags_id_seq; Type: SEQUENCE; Schema: public; Owner: camillefeghali
--

CREATE SEQUENCE public.tags_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER TABLE public.tags_id_seq OWNER TO camillefeghali;

--
-- Name: tags_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: camillefeghali
--

ALTER SEQUENCE public.tags_id_seq OWNED BY public.tags.id;


--
-- Name: tags id; Type: DEFAULT; Schema: public; Owner: camillefeghali
--

ALTER TABLE ONLY public.tags ALTER COLUMN id SET DEFAULT nextval('public.tags_id_seq'::regclass);


--
-- Data for Name: tags; Type: TABLE DATA; Schema: public; Owner: camillefeghali
--

COPY public.tags (id, name, tag_type, priority) FROM stdin;
1	Teppich	3	\N
3	Lammfell	4	\N
4	Vorhang	3	\N
5	Vorhang	4	\N
6	Ă–senschal	4	\N
7	Schal	4	\N
8	Rollo	4	\N
9	Schlaufenschal	4	\N
10	Standleuchte	3	\N
12	Bogenlampe	4	\N
13	Tischleuchte	3	\N
14	Tischleuchte	4	\N
15	Lampenschirm	4	\N
16	Deckenleuchte	3	\N
17	Deckenleuchte	4	\N
18	Deckenstrahler	4	\N
20	Kronleuchter	4	\N
21	Sessel	3	\N
23	Chaiselongue	4	\N
24	Hocker	4	\N
27	Pouf	4	\N
29	Schlafsessel	4	\N
30	Sitzhocker	4	\N
31	Sitzsack	4	\N
32	Sofa	3	\N
37	Couchtisch	3	\N
40	Beistelltisch	3	\N
41	Beistelltisch	4	\N
42	Konsolentisch	4	\N
43	Stauraum	3	\N
44	Aufbewahrungskorb	4	\N
45	BĂĽcherwand	4	\N
46	Highboard	4	\N
48	Korb	4	\N
49	Magazinhalter	4	\N
52	Schubboard	4	\N
53	Standregal	4	\N
54	Truhen-set	4	\N
55	Vitrinenschrank	4	\N
56	Wandschrank	4	\N
57	Weinregal	4	\N
58	Stauraum tv	3	\N
61	Wohnwand	4	\N
62	Stauraum wand	3	\N
63	Wandregal	4	\N
64	Tischdeko	3	\N
65	Aufbewahrungsdose	4	\N
66	Dekofigur	4	\N
67	Duftkerzen	4	\N
68	Kerzenhalter	4	\N
69	Kerzenständer	4	\N
70	Schale	4	\N
71	Schreibtischorganisation	4	\N
72	Stifthalter	4	\N
73	Tablett	4	\N
74	Teelichthalter	4	\N
75	Tischskulptur	4	\N
76	Tischuhr	4	\N
77	Vase	4	\N
78	Wanddeko	3	\N
79	Bild	4	\N
80	Bilderrahmen	4	\N
81	Kunstdruck	4	\N
82	Pinnwand	4	\N
83	Poster	4	\N
84	Wanddeko	4	\N
85	Wandskulptur	4	\N
86	Wanduhr	4	\N
87	Spiegel	3	\N
88	Spiegel	4	\N
89	Schminkspiegel	4	\N
90	Wandspiegel	4	\N
91	Planzendeko	3	\N
92	Blumentopf	4	\N
93	Pflanzenständer	4	\N
94	Textilien	3	\N
97	Tagesdecke	4	\N
98	Decke	4	\N
99	Stuhl	3	\N
100	Esstisch	3	\N
102	Schreibtisch	3	\N
103	Schreibtisch	4	\N
104	BĂĽrostuhl	3	\N
105	BĂĽrostuhl	4	\N
106	Bett, bettteil	3	\N
107	Bett, bettteil	4	\N
108	Bettwäsche	4	\N
109	Garderobe	4	\N
110	Papierkorb	4	\N
111	FuĂźmatte	4	\N
112	Aktenschrank	4	\N
113	Garderobenhaken	4	\N
114	Garderobenschrank	4	\N
115	Kleiderschrank	4	\N
116	Kleiderständer	4	\N
117	KĂĽchenschrank	4	\N
118	Rollcontainer	4	\N
119	Schuhschrank	4	\N
120	Wandhaken	4	\N
121	Baddeko	3	\N
122	Badematte	4	\N
123	Zahnputzbecher	4	\N
124	Eimer	4	\N
125	Seifenspender	4	\N
126	Wattedose	4	\N
127	Badetuch	4	\N
128	Baderost	4	\N
129	Wäschekorb	4	\N
130	Toilettenpapierhalter	4	\N
131	ToilettenbĂĽrste	4	\N
132	Bodenmatte	4	\N
133	Raumduft	4	\N
134	Baddeko	4	\N
2	Teppich	4	0
135	Minimal	0	0
138	Rund	6	0
139	Living_room	5	0
140	Uni	7	0
95	Kissen	4	0
141	Contemporary	0	0
142	Leder	2	0
143	Quadratisch	6	0
144	Bohemian	0	0
147	Modern	0	0
96	Kissenbezug	4	0
22	Sessel	4	0
19	Pendelleuchte	4	0
26	Polsterstuhl	4	0
35	Ecksofa	4	0
36	Einzelsofa	4	0
38	Couchtisch	4	0
11	Standleuchte	4	0
50	Regal	4	0
33	Sofa	4	0
47	Kommode	4	0
39	Satztisch	4	0
59	Lowboard	4	0
51	Schrank	4	0
60	Sideboard	4	0
148	Samt	2	0
145	Natur	1	0
146	Rattan	2	0
25	Ohrensessel	4	0
28	Schaukelstuhl	4	0
149	Rechteckig	6	0
150	Urban	0	0
151	Scandinavian	0	0
152	Hochflor	2	0
154	Traditional	0	0
156	Kurzflor	2	0
157	Gemustert	7	0
158	Mid century	0	0
161	Glamour	0	0
168	Gold/messing	2	1
164	Jute	2	0
191	Holz hell	1	0
174	Transparent	1	1
169	Mehrflammig	6	0
170	Direkt	7	0
175	Glas	2	1
208	Ausziehbar	7	0
172	Ohne armlehne	6	0
173	Einzel	7	0
101	Esstisch	4	0
202	Bambus	2	0
176	Nicht ausziehbar	7	0
210	Highboard	6	0
203	Samtvelours	2	0
177	Mit armlehne	6	0
178	2-sitzer (i-sofa)	6	0
179	Kein schlafsofa	7	0
181	Einflammig	6	0
182	Indirekt	7	0
183	Industrial	0	0
184	Regal	6	0
185	Offen	7	0
186	Sideboard	6	0
163	Schwarz	1	0
165	Gold	1	1
167	Metall	2	0
160	Gelb	1	0
188	Holz mittel	1	1
190	3-sitzer (i-sofa)	6	0
137	Textil	2	0
189	Holz	2	0
213	L-sofa	6	0
155	Beige	1	0
192	Geschlossen	7	0
198	Holz dunkel	1	0
204	3er-set	7	0
205	Holz mittel	2	1
193	Schlafsofa	7	0
187	Rosa	1	0
206	Mix	7	0
214	Kordsamt	2	0
194	Braun	1	0
195	Kunstleder	2	0
162	Rot	1	1
171	Kunststoff	2	1
197	2er-set	7	0
211	Läufer	6	0
209	Breit (>120)	6	0
196	Marmor	2	1
207	Schmal (<=120)	6	0
153	GrĂĽn	1	0
212	Silber	1	1
199	Oval	6	0
34	Schlafsofa	4	0
200	Gold	2	1
159	WeiĂź	1	0
136	Grau	1	0
201	Kein polsterstuhl	4	0
166	Blau	1	0
180	Beschichtet	2	0
\.


--
-- Name: tags_id_seq; Type: SEQUENCE SET; Schema: public; Owner: camillefeghali
--

SELECT pg_catalog.setval('public.tags_id_seq', 214, true);


--
-- Name: tags tags_pkey; Type: CONSTRAINT; Schema: public; Owner: camillefeghali
--

ALTER TABLE ONLY public.tags
    ADD CONSTRAINT tags_pkey PRIMARY KEY (id);


--
-- PostgreSQL database dump complete
--


I solved it by setting the allowNull to true on the priductTags model’s fields for productIdd and tagsId

  const ProductTags = sequelize.define('productTags', {
    productId: {
      type: DataTypes.BIGINT,
      primaryKey: true,
      allowNull: true,
    },
    tagsId: {
      type: DataTypes.BIGINT,
      primaryKey: true,
      allowNull: true,
    },
  }, {
    tableName: 'product_tags',
    underscored: true,
    timestamps: false,
    schema: process.env.DATABASE_SCHEMA,
  });
1 Like

@Sliman_Medini

Is there a way to have my Smart Fields be editable by Checkboxes ? currently I only have the Radio Buttons option