Mongoose text index on nested schema field - javascript

I have the following schema:
const Schema = ({
metadata: {
title: String,
...
},
...
});
and I'm looking to create a a text index on metadata.title. I can create a text index successfully on any first level property, but I'm running into trouble with the nested title.
I've tried the following code, to no avail. Is my syntax wrong? I've had no luck with docs...
Schema.index({ 'metadata.title': 'text' });
Searching:
Schema
.find(
{ $text : { $search : req.params.query } },
{ score : { $meta: "textScore" } })

It turns out what I had originally was correct, as pointed out by #JohnnyHK. I must have had some other error that caused the index to not work...

const Schema = ({
metadata: {
title: {
type: String,
index: true
}
...
},
...
});

you may have to recreate the index with the new parameters
or try to drop and recreate the collection

Related

Retrive some columns of relations in typeorm

I need to retrieve just some columns of relations in typeorm query.
I have an entity Environment that has an relation with Document, I want select environment with just url of document, how to do this in typeorm findOne/findAndCount methods?
To do that you have to use a querybuilder, here's an example:
return this.createQueryBuilder('environment') // use this if the query used inside of your entity's repository or getRepository(Environment)...
.select(["environment.id","environment.xx","environment.xx","document.url"])
.leftJoin("environment.document", "document")
.where("environment.id = :id ", { id: id })
.getOne();
Sorry I can't add comment to post above. If you by not parsed data mean something like "environment.id" instead of "id"
try this:
return this.createQueryBuilder("environment")
.getRepository(Environment)
.select([
"environment.id AS id",
"environment.xx AS xx",
"document.url AS url",
])
.leftJoin("environment.document", "document")
.where("environment.id = :id ", { id: id })
.getRawOne();
Here is the code that works for me, and it doesn't require using the QueryBuilder. I'm using the EntityManager approach, so assuming you have one of those from an existing DataSource, try this:
const environment = await this.entityManager.findOne(Environment, {
select: {
document: {
url: true,
}
},
relations: {
document: true
},
where: {
id: environmentId
},
});
Even though the Environment attributes are not specified in the select clause, my experience is that they are all returned in the results, along with document.url.
In one of the applications that I'm working on, I have the need to bring back attributes from doubled-nested relationships, and I've gotten that to work in a similar way, shown below.
Assuming an object model where an Episode has many CareTeamMembers, and each CareTeamMember has a User, something like the code below will fetch all episodes (all attributes) along with the first and last name of the associated Users:
const episodes = await this.entityManager.find(Episode, {
select: {
careTeamMembers: {
id: true, // Required for this to work
user: {
id: true,
firstName: true,
lastName: true,
},
}
},
relations: {
careTeamMembers: {
user: true,
}
},
where: {
deleted: false,
},
});
For some reason, I have to include at least one attribute from the CareTeamMembers entity itself (I'm using the id) for this approach to work.

Mongo cyclic dependency detected while creating index

I have a data with structure like this:
And I try to write a query $near. For this query, I have to create index, but I get error cyclic dependency detected . Here is my code:
define model
var answers = new Schema({
countdown: String,
location: Object,
}, {
collection: 'test'
});
var Model = mongoose.model('Model', answers);
build and call query
Model.collection.createIndex({ "point": "2dsphere" });
//query = { location : { $near : [ -120.24, 39.21 ], $maxDistance: 0.10 } }
query = {
location: {
$near: {
$geometry: {
coordinates: [-120.24, 39.20 ]
},
$maxDistance: 1000
}
}
}
}
Model.find(query, function ...)
Could you please help me to solve it?..
You can use MONGO SHELL to create indices. Login with the connection string and select your DB and Collection and run
db.collection_name.createIndex({"field_name": "indexing value"})
This should solve the issue.
location.coordinates field must be an array of numbers, in your case it is an array of strings. You should change the fields type to Double.

Upsert data with a dynamic field name

I just try to do something simple with Mongo but it doesn't work:
I want to upsert datas in an object like: module.xxx.yyy then I tried many things like :
UsersRights.upsert({
condoId: condoId,
userId: manager._id,
}, {
condoId: condoId,
userId: manager._id,
module: {
[defaultRight.xxx] : {
[defaultRight.yyy] : defaultRight.default
}
}
});
but when I want to add a new xxx or a new yyy, it will erase and replace the entire module object and not only add a new key.
I also tried this :
UsersRights.upsert({
condoId: condoId,
userId: manager._id,
}, {
condoId: condoId,
userId: manager._id,
["module." + defaultRight.module + "." + defaultRight.right] : defaultRight.default,
});
but the server show me an error like: MinimongoError: Key module.xxx.yyy must not contain '.'
You need to use the following form:
YourCollection.upsert({
_id: id, (can be other selectors as well)
}, {
$set: setter
});
Setter is an object you create before and should have the following form:
const setter = {};
setter[`${#1Level}.${#2Level}`] = data;
Where #1Level & #2Level are vars naming the fields you want to modify or to add.

pg-promise ColumnSet use Postgres functions with def property

I am using a ColumnSet and the helper.insert function for a multi row insert.
I have a table column where I want to use the Postgres Date/Time now() function.
const cs = new helpers.ColumnSet([
'lastname',
{
name: 'rental_date',
def: 'now()'
}
], { table: { table: 'book_rental', schema: 'public' } })
let rentals = [
{
lastname: 'Mueller'
},
{
lastname: 'Johnson'
}
]
let insert = helpers.insert(rentals, cs)
db.result(insert)
.then(data => res.json({ message: 'Ok!' }))
.catch(err => res.json({ message: 'Not ok!' }))
It seems to be working by using def: 'now()', but I want to make sure that I am using it the right way.
Edit:
Regarding the answer in the comment. I tried to do the insert manually and it looks like Postgres is converting the 'now()' string into the now() function.
INSERT INTO book_rental (lastname, rental_date) VALUES ('Mueller', 'now()');
To involve your answer, am I right that this should be the correct code then?
const cs = new helpers.ColumnSet([
'lastname',
{
name: 'rental_date',
mod: ':raw',
def: 'now()'
}
], { table: { table: 'book_rental', schema: 'public' } })
Your code doesn't look right, for the following reasons:
You want to use now() without any condition, but the def value is only used when the property doesn't exist in the source object (see Column). The init callback is what should be used instead to guarantee the right value override.
You return now() as an escaped string, while the query needs it as a raw-text string.
First, let's declare a reusable Raw Text string, as per Custom Type Formatting:
const rawText = text => ({toPostgres: () => text, rawType: true});
Then you can define the column like this:
{
name: 'rental_date',
init: () => rawText('now()')
}
And make sure you are using the latest version of pg-promise (v7.2.1 as of this writing).
Or alternatively, you can declare it like this:
{
name: 'rental_date',
mod: ':raw', // same as mode: '^'
init: () => 'now()'
}
This syntax however will work in all versions of the library, and perhaps is even simpler to use ;)

Model not associated with Model Sequelize

I'm trying to esatblish a One-To-Many relationship between the tables: Exam and Exam_Questions, using Sequelize.
Even though the tables are created properly and I can see them in PhpMyAdmin, I keep getting the following error in console:
Error: exam_question is not associated to exam!
exam.js
...
const ExamQuestion = require('./exam-question');
...
const Exam = sequelizeInstance.define("exam", {
name: { type: Sequelize.STRING },
date: { type: Sequelize.DATE }
});
// Build the model relations
Exam.hasMany(ExamQuestion, { as: "Questions" });
exam-question.js
const ExamQuestion = Sequelize.db.define("exam_question", {
correct_answer: {
type: Sequelize.STRING
},
text: {
type: Sequelize.STRING
}
});
module.exports = ExamQuestion;
To solve the error, I tried:
ExamQuestion.belongsTo(Exam);
But that doesn't change anything.
The query is:
Exam.findAll({
include: [ExamQuestion]
})
How to fix this problem and get the Exam objects including their questions?
TL;DR
For some very non-intuitive reason this seems to be happening because of the as property. To fix the problem, simply remove the as property:
Exam.hasMany(ExamQuestion);
Fixing the methods
By default, after removing the as property, Sequelize will automagically add the following methods: getExam_questions, addExam_question and so on.
They look quite bad: camel and snake cases mixed up together.
To solve that, we can easily define the singular and plural names in the ExamQuestion model options (the third argument):
const ExamQuestion = Sequelize.db.define("exam_question", {
correct_answer: {
type: Sequelize.STRING
},
text: {
type: Sequelize.STRING
}
}, {
name: {
singular: "question",
plural: "questions"
}
});
This will dictate Sequelize to create methods such as getQuestions and addQuestion instead of getExam_questions and addExam_question.

Categories