mujz / pg-search-sequelize Goto Github PK
View Code? Open in Web Editor NEWPostgres full-text search in Node.js and Sequelize.
License: MIT License
Postgres full-text search in Node.js and Sequelize.
License: MIT License
When I attempt to migrate using sequelize-cli, I get the following error:
Cannot read property 'describe' of undefined
My migration file is as follows:
const QueryInterface = require('pg-search-sequelize').QueryInterface;
const models = require('../src/data/models');
import Sequelize from 'sequelize'
// The model we're creating the materialized view for
const materializedViewName = 'source_materialized_view';
const attributes = { // field: weight. Every field has a weight to calculate how relevant the search results are.
title: 'A', // name has the highest weight.
category: 'B',
url: 'D', // city has a lower weight than title and description
};
const options = {
include: [ // You can also include fields from associated models
{
model: models.Tag,
foreignKey: 'tag_id',
targetKey: 'id',
associationType: 'belongsToMany', // association types are: belongsTo, hasOne, or hasMany
attributes: { // Those attributes get added to the materialized view's search document and will also be searched just like the other fields
keywords: 'C',
},
},
],
};
module.exports = {
up: queryInterface => new QueryInterface(queryInterface).createMaterializedView(materializedViewName, models.Source, attributes, options),
down: queryInterface => new QueryInterface(queryInterface).dropMaterializedView(materializedViewName),
};
Hi Guys, I'm using this package to make full text searches in my current system. I've followed the steps on how to implement the materialized views suggested on the documentation with no luck. I'm getting the following error
TypeError: Cannot read property 'field' of undefined
at Object.keys.forEach.key (~/proj/node_modules/pg-search-sequelize/lib/queryGenerator.js:100:59)
at Array.forEach (native)
at QueryGenerator.where (~/proj//node_modules/pg-search-sequelize/lib/queryGenerator.js:97:29)
at Function.search (~/proj/node_modules/pg-search-sequelize/lib/searchModel.js:82:8)
I've been trying to debug to see if I've implemented incorrectly but, it looks very alike to the example provided. I'll post the corresponding code below:
Express router
directorsRouter.get('/search',role_auth.isAdmin, (request, response) => {
let query = request.query ? request.query.q : 400;
if(query === 400) {
return response.json({
status: query,
})
} else {
return models.DirectorMaterializedView.searchByText(query).catch(console.log);
}
})
User.js (reference model)
'use strict';
let SearchModel = require("pg-search-sequelize");
module.exports = (sequelize, DataTypes) => {
const user = sequelize.define('user', {
name: {
type: DataTypes.STRING
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
password: {
type: DataTypes.STRING,
allowNull: false
},
role_id: {
allowNull: false,
type: DataTypes.INTEGER,
references: {
model: "role",
key: "id"
}
},
profile_pic: {
type: DataTypes.STRING
}
});
user.associate = (models) => {
user.belongsTo(models.role, {
foreignKey: 'role_id'
})
user.hasMany(models.director, {
foreignKey: 'user_id',
onDelete: 'CASCADE'
})
user.hasMany(models.teacher, {
foreignKey: 'user_id',
onDelete: 'CASCADE'
})
user.hasMany(models.student, {
foreignKey: 'user_id',
onDelete: 'CASCADE'
})
}
user.hook("beforeCreate", "passwordHashing", (user, options) => {
let hashedPassword = passwordHelper.hash(user.password)
return user.password = hashedPassword
})
user.hook("afterCreate", "emailNotification", (user, options) => {
// Asynchronous way to send an email without
// interrupting the flow of the system
Mailer.sendPasswordWelcomeTemplate(user)
.then(console.log)
.catch(console.log)
return user;
})
return user;
};
Materialized view implementation
'use strict';
const models = require("../models");
let SearchModel = require("pg-search-sequelize");
module.exports = (sequelize, DataTypes) => {
let DirectorMaterializedView = sequelize.define('DirectorMaterializedView', {
id: {type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true},
name: DataTypes.STRING,
email: DataTypes.TEXT,
profile_pic: DataTypes.TEXT
}, {
tableName: 'director_materialized_view',
timestamps: false,
search: true,
defaultScope: {
attributes: {
exclude: ['profile_pic', 'id']
}
},
referenceModel: 'user' // The model for which we're defining the materialized view
});
return DirectorMaterializedView;
};
Index.js
fs
.readdirSync(__dirname)
.filter(file =>
(file.indexOf('.') !== 0) &&
(file !== basename) &&
(file.slice(-3) === '.js'))
.forEach(file => {
const model = sequelize.import(path.join(__dirname, file));
models[model.name] = model;
});
Object.keys(models).forEach(key => {
let model = models[key];
if ('associate' in model) model.associate(models);
if ('referenceModel' in model.options) model.referenceModel = models[model.options.referenceModel];
if ('search' in model.options) new SearchModel(model);
if ('customHooks' in model.options && 'afterSave' in model.options.customHooks) {
let callback = () => model.options.customHooks.afterSave(models);
model.afterCreate(callback);
model.afterBulkCreate(callback);
model.afterDestroy(callback);
model.afterBulkDestroy(callback);
model.afterUpdate(callback);
model.afterBulkUpdate(callback);
}
});
models.sequelize = sequelize;
models.Sequelize = Sequelize;
module.exports = models;
Sequelize migration
'use strict';
const QueryInterface = require("pg-search-sequelize").QueryInterface;
const models = require("../models");
const referenceModel = models.user;
const materializedViewName = "director_materialized_view";
const attributes = {
name: "B",
email: "A"
}
const options = {
primaryKeyField: "id",
include: [
{
model: models.director,
foreignKey: "user_id",
targetKey: "id",
associationType: "hasOne",
attributes: {
phone: "D"
}
}
]
}
module.exports = {
up: queryInterface => new QueryInterface(queryInterface).createMaterializedView(materializedViewName, referenceModel, attributes, options),
down: queryInterface => new QueryInterface(queryInterface).dropMaterializedView(materializedViewName)
};
Any help with this will be greatly appreciated.
Extra information:
Is there e possibility to define scopes like this:
await models.MaterializedModel.scope('active').search(query);
and more importantly, I wish to use a dynamic scope like this:
await models.MaterializedModel.scope({ method: ['visibleFor', session] }).search(query);
Thank you for your time
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.