Question

Ok, so I have, what seems to me like a very weird issue. I have a Postgres table created with the following SQL:

CREATE TABLE message
(
  message text,
  author integer,
  thread integer,
  id serial NOT NULL,
  "createdAt" timestamp with time zone,
  "updatedAt" timestamp with time zone,
  CONSTRAINT message_pkey PRIMARY KEY (id)
)
WITH (
  OIDS=FALSE
);
  ALTER TABLE message
  OWNER TO glenselle;

I'm using Sails.js (which uses Waterline ORM) to save a message model to the database. Mind you, in the process of trying to isolate the problem I began dropping the table every time I try saved a new record and the behavior is always the same. The ORM is doing some associations for me to associate the author with a user model and the thread with a thread model. Anyway, when I attempt to save a record, I first get this:

ERROR:  duplicate key value violates unique constraint "message_pkey"
DETAIL:  Key (id)=(1) already exists.
STATEMENT:  INSERT INTO "message" ("message", "author", "thread", "id", "createdAt", "updatedAt") values ($1, $2, $3, $4, $5, $6) RETURNING *

So this should be really easy to understand. There's already a row in the table with an id of 1 which is why the "message_pkey" constraint is violated. But the ironic thing is that there is no data! So my question is this, what could be happening that causes Postgres to throw a unique constraint violation if the table has absolutely no data in it (it was just dropped and recreated it with the SQL I posted above)?

Here's what I'm running to create the model:

create: function(req, res) {
    var self = this;

    Thread.create({}, function(err, newThread) {
        if(err) return console.log(err);

        Message.create({message: req.body.conversation[0].message}, function(err, newMessage) {
            if(err) return console.log(err);
            // This returns an array of user ids
            sails.controllers.thread.parseUserIds(req.body.participants, req.user, function(idList) {

                // First, associate the message with the author
                newMessage.author = req.user.id;
                newMessage.save(function(err, savedMessage) {
                    if(err) return console.log(err);

                    // First, associate the participants with the thread
                    newThread.participants.add(idList);

                    // Next, associate the message with the thread
                    newThread.conversation.add(savedMessage);

                    newThread.save(function(err, savedThread) {
                        if(err) return console.log(err);

                        console.log('The thread looks to have been saved. Check it out!');
                        return res.json(savedThread);
                    });
                });
            });
        });
    });
},
Was it helpful?

Solution

You're attempting to pass a model instance to newThread.conversation.add, which is a shortcut for "create and add". To add an existing instance to a collection, you need to pass its ID. Change the line to:

newThread.conversation.add(savedMessage.id);

and it should work.

A couple of other points:

  1. Rather than accessing a controller method directly via sails.controllers.thread.parseUserIds, you might consider moving that code into a service (in the /api/services) folder. Services are automatically globalized by Sails and can be accessed from any controller.
  2. If you're attempting to pass in an array of IDs to newThread.participants.add, that will end up failing as well. You'll need to loop through the array and call add with each individual element.

Support for IDs (and passing existing instance objects) will likely be added in the near future, but we didn't want to let bells and whistles delay the release of baseline associations support. Make those adjustments and your code should work now!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top