MongoError: text index required for $text query - node.js

I am getting text index required for $text query where as i already did index before using that schema. Can someone tell me what could be the issue?. One more question Do we need to drop table in mongodb to create index? if yes then i will loose my current data. how can i do indexing without dropping the table?
const mongoose = require('mongoose');
let UserSchema = new mongoose.Schema({
email: String,
title: String,
});
UserSchema.indexes({ email: 'text', title: 'text' });
run().catch((err) => console.log(err));
async function run() {
await mongoose.connect('mongodb://localhost:27017/test', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
await mongoose.connection.dropDatabase();
const UserModel = mongoose.model('user', UserSchema);
await UserModel.createIndexes();
const newUser = [
{ email: 'test#test.com', title: 'r' },
{ email: 't#gmail.com', title: '#ro' },
];
const user = await UserModel.create(newUser);
console.log(user, 'user');
const index = await UserModel.listIndexes();
console.log(index);
const data = await UserModel.find({ $text: { $search: 'test' } }).exec();
console.log(data);
}

The function UserSchema.indexes returns the current indexes that are defined on the schema. You want UserSchema.index that defines a new index.

Related

Error while updating mongo db object by id

I am trying to update my mongodb database by Id but I am getting error userId.save is not a function. What I did was get all the databases data by Object.findById then used Object.assign to assign an updated value to the specified key then saved the updated Object back to the database. Where did I go wrong. How can I update a mongodb object by Id. Thanks in advance.
const Users = require('pathToSchema')
const userId = Users.findById('ObjectId')
Object.assign(userId, '{"email": "test#gmail.com"}')
//error arrises here. "userId.save is not a function"
userId.save()
.then((result) => {
console.log(result)
})
.catch((err) => {
console.log(err)
})
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const users_Schema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
}
}, {timestamps: true})
const Users = mongoose.model('users', users_Schema)
module.exports = Users;
The findById is not execute yet. You have to use it with a callback or an exec(). You can learn more at mogoose doc.
Try change line const userId = Users.findById('ObjectId') to const userId = await Users.findById('ObjectId').exec(). exec() will return a promise, so you could use await to get result.
Furthermore, the Object.assign statement is not correct, there is no need for the string character (which is '). It's just Object.assign(userId, {"email": "test#gmail.com"})
Try assigning the email prop instead of using Object.assign. Also bear in mind that you need to assign 2 objects but you assign a string instead.
Try this:
const userId = await Users.findById('ObjectId')
userId.email = 'test#gmail.com';
userId.save()
.then((result) => {
console.log(result)
})
.catch((err) => {
console.log(err)
})
Also, make sure you create a model from the schema and use it to findById. For instance:
const UserSchema = new Schema({
name:String,
username:{type:String, required:true, index:{unique:true}},
password:{type:String, required:true, select:false}
});
const UserModel = mongoose.model('User', UserSchema);
const user = await UserModel.findById(...);
user.save();
This worked for me.
Users.findById('ObjectId')
.then((result) => {
Object.assign(result, {
"email": "test#gmail.com"
})
result.save()
.then((result) => {
console.log(result)
})
.catch((err) => {
console.log(err)
})
})
.catch((err) => {
console.log(err)
})

Getting an empty array Mongoose

I can not get data from my MongoDb collection via mongoose - I'm getting an empty array out of my request. It only happens when I'm using a route which I posted below.
Code
router.get("/options", async (req,res) => {
try {
const { animalClass} = req.body;
if (!animalClass) {
const animalClasses = await AnimalClass.find({});
console.log(animalClasses);
return res
.status(200)
.json({animalClasses})
} else {
const animalTypes = await AnimalType.find({class: animalClass});
console.log(animalTypes);
return res
.status(200)
.json({animalTypes})
}
} catch (err) {
res
.status(500)
.json({msg: err})
}
});
Schema
const mongoose = require('mongoose');
const animalClassSchema = new mongoose.Schema({
name: {type: String, required: true}
})
module.exports = AnimalClass = mongoose.model('animalClass',animalClassSchema);
Specify the collection name when creating the schema, like:
const animalClassSchema = new mongoose.Schema({
name: {type: String, required: true}
}, { collection: 'animalClass' });
By default, Mongoose pluralizes your collection name. This option allows you to override that behavior. More info in the docs:
https://mongoosejs.com/docs/guide.html#collection

array of object populate returns null mongoose

This returns null what could be the issue? I see proper user _id in the test table, I would expect user detail to be shown in the place user. As you can see under test array i made ref to user schema.
structure as follows in database
const mongoose = require('mongoose');
let UserSchema = new mongoose.Schema({
email: String,
password: String,
});
let testSchema = new mongoose.Schema({
test: [
{
title: String,
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'user',
},
},
],
});
run().catch((err) => console.log(err));
async function run() {
await mongoose.connect('mongodb://localhost:27017/test', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
await mongoose.connection.dropDatabase();
const UserModel = mongoose.model('user', UserSchema);
const TestModel = mongoose.model('test', testSchema);
const newUser = { email: 'test#test.com', password: 'Alexa123' };
const user = new UserModel(newUser);
await user.save();
const newTest = { test: [{ title: 'foo', user: user._id }] };
const test = new TestModel(newTest);
await test.save();
const getTest = await TestModel.findOne({ title: 'test' })
.populate('test.user')
.exec();
console.log(getTest, 'returns null');
}
anyway solved by this
const getTest = await TestModel.findOne({ _id: test._id })
.populate('test.user')
.exec();

mongoose.Schema.Types.ObjectId is giving an empty array when console.logged

This is my table schema
var mongoose=require("mongoose");
var tableSchema=new mongoose.Schema({
tName:String,
keys:[
{
type:mongoose.Schema.Types.ObjectId,
ref:"key"
}
],
fields:[
{
type:mongoose.Schema.Types.ObjectId,
ref:"field"
}
]
})
module.exports=mongoose.model("table",tableSchema);
----Key Schema
var mongoose=require("mongoose")
var keySchema=new mongoose.Schema({
name:[String],
value:[String]
})
module.exports=mongoose.model("key",keySchema);
---field Schema
var mongoose=require("mongoose")
var fieldSchema=new mongoose.Schema({
name:[String],
value:[String]
})
module.exports=mongoose.model("field",fieldSchema);
----How I Pushed into
app.post("/table/:id/value",function(req,res){
var Key={
name:req.body.key,
value:req.body.keyValue
}
var Field={
name:req.body.field,
value:req.body.fieldValue
}
table.findById(req.params.id,function(err,foundTable){
if(err){
console.log(err)
}
else{
console.log(foundTable)
key.create(Key,function(err,createKey){
foundTable.keys.push(createKey)
console.log(createKey)
})
field.create(Field,function(err,createField){
foundTable.fields.push(createField)
console.log(createField)
})
foundTable.save();
console.log(foundTable);
res.redirect("/table/"+req.params.id)
}
})
})
ObjectId are not being refernced
Here is the Image that prints the table
How I populated the table
app.get("/table/:id",function(req,res){
table.findById(req.params.id).populate("keys").populate("fields").exec(function(err,foundTable){
if(err){
console.log(err)
res.redirect("/")
}
else{
console.log(foundTable);
res.render("show",{table:foundTable})
}
})
})
I Dont know where I had gone wrong,
everything seems to be fine but
the objected is not referenced when printed and
it is not being populated
How it should be printed reference: https://bezkoder.com/mongoose-one-to-one-relationship-example/
This is an example:
1st schema
const mongoose = require("mongoose");
const Customer = mongoose.model(
"Customer",
new mongoose.Schema({
name: String,
age: Number,
gender: String
})
);
module.exports = Customer;
2nd schema
const mongoose = require("mongoose");
const Identifier = mongoose.model(
"Identifier",
new mongoose.Schema({
cardCode: String,
customer: {
type: mongoose.Schema.Types.ObjectId,
ref: "Customer"
}
})
);
module.exports = Identifier;
How it should be printed
{
_id : ObjectId("5da000be062dc522eccaedeb"),
cardCode : "5DA000BC06",
customer : ObjectId("5da000bc062dc522eccaedea"),
__v : 0
}
How it should be populated
[ { _id: 5da135bf61a1dd3e9c2a6e82,
cardCode: '5DA135BD61',
customer:
{ _id: 5da135bd61a1dd3e9c2a6e81,
name: 'bezkoder',
age: 29,
gender: 'male',
__v: 0 },
__v: 0 } ]
try this .populate([ 'keys', 'fields' ])
The reason why keys and fields are not inserted is that the foundTable.save() will be executed before creating the new Key and Field documents and push there _id to the foundTable.
One way to solve the issue is by using async/await. You can modify your code as below using async/await
app.post("/table/:id/value", async function (req, res) {
var Key = {
name: req.body.key,
value: req.body.keyValue,
};
var Field = {
name: req.body.field,
value: req.body.fieldValue,
};
try {
const foundTable = table.findById(req.params.id);
const createKey = await key.create(Key);
const createField = await field.create(Field);
foundTable.keys.push(createKey._id);
foundTable.fields.push(createField._id);
await await foundTable.save();
res.redirect("/table/"+req.params.id)
} catch (err) {
console.log(err);
// handle failure here
}
});
This will make sure the Key and Field are created and _id is pushed to foundTable before saving the foundTable
Regarding the populate query. Looks like once you save the _id of Field and Key in foundTable your existing query itself should work

How to automatically create a required field in mongoose

I have a mongoose schema that looks like this:
var userSchema = new Schema({
username: {type: String, required: true, index: {unique: true}},
usernameCanonical: {type: String, required: true, index: {unique: true}}
});
userSchema.pre("save", function () {
this.usernameCanonical = this.username.toLowerCase();
return next();
});
I want to be able to create new users by only entering a username, and let usernameCanonical get generated by the model automatically.
var user = new User({
username: "EXAMPLE_USERNAME"
});
user.save()
When I try to do this I get a validation error from mongoose saying that usernameCanonical is required.
Path `usernameCanonical` is required.
The problem seems to be that the pre-save hooks get called after validation. I don't want to have to manually add a canonical username every time I save a new user. I also don't want to remove the required option from the schema.
Is there some way to get a mongoose model to automatically generate a required field? Adding a default value to the usernameCanonical field in the schema seems to prevent the validation error, but it feels like a hack.
As levi mentioned, you should use the validate() hook:
Save/Validate Hooks
Check this working example based on your code:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const userSchema = new Schema({
username: {type: String, required: true, index: {unique: true}},
usernameCanonical: {type: String, required: true, index: {unique: true}}
});
userSchema.pre('validate', function () {
if ((this.isNew || this.isModified) && this.username) {
this.usernameCanonical = this.username.toLowerCase();
}
});
const User = mongoose.model('user', userSchema);
mongoose.connect('mongodb://localhost:27017/uniqueTest')
.then(() => {
// create two users
const user1 = new User({
username: 'EXAMPLE_USERNAME-1'
});
const user2 = new User({
username: 'EXAMPLE_USERNAME-2'
});
return Promise.all([
user1.save(),
user2.save()
]);
})
.then(() => {
// update username
return User.findOne({ username: 'EXAMPLE_USERNAME-1' })
.then((user) => {
user.username = 'EXAMPLE_USERNAME_UPDATED-1';
return user.save();
});
})
.then(() => mongoose.connection.close())
.then(() => console.log('script finished successfully'))
.catch((err) => {
console.error(err);
mongoose.connection.close()
.then(() => process.exit(1));
});
I hope this helps.

Resources