Chris Wilson
Chris Wilson

Reputation: 6719

How to create unique keys in KeystoneJS

I'm working on a site built in KeystoneJS that allows users to post words and get suggested synonyms from other users. Words are submitted as part of a phrase or sentence, like "The cat was [perilously] close to knocking over the glass."

My Sentence model looks like this:

Sentence.add({
    sentence: { type: Types.Text, required: true, initial: "New Sentence", index: true },
    word: { type: Types.Relationship, ref: 'Word', required: true, index: true, unique: true, initial: true },
    submitter: { type: Types.Relationship, ref: 'User', required: true, index: true, unique: true, initial: true },
    source: { type: Types.Text },
    createdAt: { type: Date, default: Date.now }
});

And I tried to make the Word model unique according to Mongoose docs:

var Word = new keystone.List('Word', { 
    map: { name: 'word' },
    _id: { from: 'word', path: 'word', unique: true, fixed: false}
});

Word.add({
    word: { type: Types.Text, required: true, initial: "New word", index: true }
});

But if I test it by submitting two sentences with the same word, it just makes a second instance of that word with the _id [word]-1, [word]-2, etc.

I need to be able to query all sentences that use a particular word, so I really need one item per word. But for the life of me, I can't figure out how to make a field unique.

It's possible my problem is with when I add a new Word from the route responsible for accepting AJAX requests:

var newWord = new Word.model({
    word: req.body.word // read from the input box on the home page
});

newWord.save(function(err) {
    if (err) {
        console.error(err);
    }
});

But I thought .save would just update an existing unique field?

Upvotes: 12

Views: 1985

Answers (2)

Chris Wilson
Chris Wilson

Reputation: 6719

I was only able to enforce the uniqueness by using the mongoose-unique-validator module like so:

var keystone = require('keystone');
var Types = keystone.Field.Types;
var uniqueValidator = require('mongoose-unique-validator');

var Word = new keystone.List('Word', { 
    map: { name: 'word' }
});

Word.add({
    word: { type: Types.Text, index: true, unique: true }
});

Word.schema.plugin(uniqueValidator);

Word.defaultColumns = 'word';

Word.register();

Upvotes: 3

davide bubz
davide bubz

Reputation: 1329

you need to change the add method of your model like this:

Word.add({
    word: { type: Types.Text, required: true, initial: "New word", index: true, unique: true }
});

i tried it and worked for me, notice i added unique:true

i created a keystone project using yeoman's keystone generator, and created a model like yours (you can find it in model/Test.js), then in the admin page when i try to add the same word twice i get:

Error saving changes to Word 569b98f27b5786db1c367b7a:
{ [MongoError: E11000 duplicate key error collection: test_unique_field.words index: word_1 dup key: { : "test" }]
  name: 'MongoError',
  code: 11000,
  err: 'E11000 duplicate key error collection: test_unique_field.words index: word_1 dup key: { : "test" }' }

this is the link to the repo if you want to play with it: keystonejs_test_unique

Upvotes: 3

Related Questions