Search code examples
node.jsmongodbmongoosekeystonejsnosql

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?


Solution

  • 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();