Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 483
Chris Wilson Avatar asked Jan 07 '16 21:01

Chris Wilson


People also ask

What is keystonejs and how does it work?

The KeystoneJS tutorial focuses on building a content management system as fast as possible and fleshing out secure APIs. KeystoneJS definitely saves a developer a lot of time during development because of the amazing out-of-the-box features.

What is the use of createcontext in Keystone?

This lets you interact with the node http.Server that Keystone uses. async createContext (req, res): A function you can call to create a Keystone Context for the request graphqlSchema - this is the keystone graphql schema that can be used in a WebSocket GraphQL server for subscriptions

How to create a unique key constraint in SQL?

This is the basic SQL syntax for creating a unique key constraint using the CREATE TABLE clause. The parameters used here are: CREATE TABLE: This statement is used for creating a new table in a database. Column_name1, Column_name2,Column_name3: Mention the name of columns you want to create in the table.

What is the use of presentation layer in keystonejs?

In KeystoneJS, it serves as the busines logic layer that contains the logic that accesses the model, otherwise known as controllers. It serves as a bridge between the models and templates. Presentation - Templates: This is the presentation layer. It displays data on the screen.


2 Answers

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

like image 155
davide bubz Avatar answered Sep 20 '22 19:09

davide bubz


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();
like image 20
Chris Wilson Avatar answered Sep 19 '22 19:09

Chris Wilson