"Cannot read property 'apply' of undefined"? in loopback 3 - loopback

i don't know why i have this error
when i executing the method in the loopback explorer gives the error
This is the .js file used in the project
'use strict';
module.exports = function(Puntoventa) {
var app = require('../../server/server');
Puntoventa.getAll = function() {
Puntoventa.find({ where: { nombre: !null } }, function(err, punto) {
if (err) return callback(err);
return punto;
});
}
}
and this is the model .json
"name": "puntoVenta",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"acls": [],
"methods": {
"getAll": {
"accepts": [],
"returns": [{
"arg": "punto",
"type": "object",
"root": true,
}],
"http": [{
"path": "/getAll",
"verb": "get"
}]
}
}

The error is due to a bug in sql query, you cannot use !null instead you can use neq given by loopback
Puntoventa.find({ where: { nombre: { "neq": null} } }, function(err, punto) {
if (err) return callback(err);
return punto;
});

Please use { "neq": null} } and define callback in getAll().
Puntoventa.getAll = function(callback) {
Puntoventa.find({ where: { nombre: { "neq": null} } } }, function(err, punto) {
if (err) return callback(err);
return callback(null,punto);
});
}

Related

Search MongoDB autocomplete filtered

I want to search autocomplete on the following fields :contactfirstname, contactlastname and name
Also, want to filter based on userid(s) first then perform autocomplete search
Issue:
Without filter criteria, autocomplete is working fine
With filter criteria in compound query not working as getting empty array
Can anyone help please?
exports.userNameCitySearchAutocomplete = async function (req, res) {
try {
const { userNameCityQueryparam } = req.query;
console.log("search query param", userNameCityQueryparam);
const agg = [
{
$search: {
index: 'userNameCity',
'compound': {
"filter": [{
"text": {
"query": ["6271f2bb79cd80194c81f631"],
"path": "_id",
}
}],
"should": [
{
//search on user name
autocomplete: {
query: userNameCityQueryparam,
path: 'name',
fuzzy: {
maxEdits: 2,
prefixLength: 3
}
}},
//search on user city
{
autocomplete: {
query: userNameCityQueryparam,
path: 'city',
fuzzy: {
maxEdits: 2,
prefixLength: 3
}
},
}
,
//search on user contact first name
{
autocomplete: {
query: userNameCityQueryparam,
path: 'contactfirstname',
fuzzy: {
maxEdits: 2,
prefixLength: 3
}
},
}
,
//search on user contact last name
{
autocomplete: {
query: userNameCityQueryparam,
path: 'contactlastname',
fuzzy: {
maxEdits: 2,
prefixLength: 3
}
},
}
],
"minimumShouldMatch": 1
}
}
}
]
const response = await User.aggregate(agg);
return res.json(response);
// res.send(response);
} catch (error) {
console.log("autocomplete search error", error);
return res.json([]);
}
};
Index details in mongodb:
{
"mappings": {
"dynamic": false,
"fields": {
"_id": {
"type": "string"
},
"city": {
"type": "autocomplete"
},
"contactfirstname": {
"type": "autocomplete"
},
"contactlastname": {
"type": "autocomplete"
},
"name": {
"type": "autocomplete"
}
}
}
}
Image of collection in mongodb
image of empty array
for anyone looking for solution to this,
You can use the MQL where clause in your pipeline stage definition.
{
$match: {
email:"email#domain.com"
}
}
check here for an example

How to populate array of objects in mongoose

I have this code -
const getAllCourses = async (req, res) => {
const courses = await Course.find({});
try {
await courses.populate('professor')
res.send({ status: 200, data: { courses } });
} catch (err) {
res.status(500).send({ status: 500, message: "Internal server error." });
}
};
Also, this is the response I'm getting from postman -
{
"status": 200,
"data": {
"courses": [
{
"_id": "61dc47f58f88c1a7e9bd36b6",
"name": "Course1",
"professor": "61dc1299431cd669faad7d0f",
"students": [
{
"student": "61dc0b7f103b531f105e8e4c",
"_id": "61dc47f58f88c1a7e9bd36b7"
},
{
"student": "61dc220885886a9f1d8e94d0",
"_id": "61dc47f58f88c1a7e9bd36b8"
}
],
"createdAt": "2022-01-10T14:51:33.313Z",
"updatedAt": "2022-01-10T14:51:33.313Z",
"__v": 0
},
{
"_id": "61dc47fb8f88c1a7e9bd36bf",
"name": "Course2",
"professor": "61dc1299431cd669faad7d0f",
"students": [
{
"student": "61dc0b7f103b531f105e8e4c",
"_id": "61dc47fb8f88c1a7e9bd36c0"
},
{
"student": "61dc220885886a9f1d8e94d0",
"_id": "61dc47fb8f88c1a7e9bd36c1"
}
],
"createdAt": "2022-01-10T14:51:39.704Z",
"updatedAt": "2022-01-10T14:51:39.704Z",
"__v": 0
}
]
}
}
Now what I'm trying to do is to populate the professor and the students but it doesn't seem to work.
I tried populating "courses.professor", "course.professor", "professor" but nothing worked for me.
What am I missing?
Here is an example of how this can be done for a document with an array friends on it:
User.
findOne({ name: 'Val' }).
populate({
path: 'friends',
// Get friends of friends - populate the 'friends' array for every friend
populate: { path: 'friends' }
});
I just solved it by chaining the populate method directly after the Course.find({}) and it just worked, I'm not sure why though.
Solution:
const getAllCourses = async (req, res) => {
const courses = await Course.find({}).populate('professor').populate('students.student');
try {
res.send({ status: 200, data: { courses } });
} catch (err) {
res.status(500).send({ status: 500, message: err.message });
}
};

how do i push a document on a nested mongodb

if I want to add a review, with author,rating and reviewText to the first title, how do I do it.
{
"_id": ObjectId("58dd21c3cb77090b930b6063"),
"bookAuthor": "wwww",
"titles": [{
"title": "this is title",
"_id": ObjectId("58dd3f2701cc081056135dae"),
"reviews": [],
"favouredBy": [
"bb, aa, cc"
]
}, {
"title": "this is the second tittle",
"_id": ObjectId("58dd42a59f12f110d1756f08"),
"reviews": [],
"favouredBy": [
"all"
]
}],
"__v": 0
}
from with in the application this is what I tried but keep getting "TypeError: Cannot read property 'push' of undefined" error
module.exports.reviewsCreate = function(req, res) {
if (req.params.bookid) {
Bok
.findById(req.params.bookid)
.select('titles')
.exec(
function(err, book) {
if (err) {
sendJSONresponse(res, 400, err);
} else {
doAddReview(req, res, book);
}
}
);
} else {
sendJSONresponse(res, 404, {
"message": "Not found, bookid required"
});
}
};
var doAddReview = function(req, res, book, author) {
console.log(book);
if (!book) {
sendJSONresponse(res, 404, "bookid not found");
} else {
book.titles.reviews.push({
author: author,
rating: req.query.rating,
reviewText: req.query.reviewText
});
book.save(function(err, book) {
var thisReview;
if (err) {
sendJSONresponse(res, 400, err);
} else {
sendJSONresponse(res, 201, book);
}
});
}
};

how to write findOneAndUpdate query in express.js?

i have shown my data , which is stored in database like this
{
"_id": {
"$oid": "5799995943d643600fabd6b7"
},
"Username": "xx",
"Email": "xx#gmail.com",
"Info": "Deactivate",
"Description": "aajdjdjddjdkjddjdjdhdj",
"VerificationCode": "594565",
"VerificationExpires": {
"$date": "2016-10-07T10:20:20.077Z"
}
}
My controller:
if Username, Email, Info are matched I need to update " Info = 'Active' " this is working at the same time i need to delete 'VerificationCode' field and 'VerificationExpires' field how can i achieve this?
exports.updatearticle = function(req, res) {
Article.findOneAndUpdate(
{ "Username":'xx', "Email":'xx#gmail.com', "Info": "Deactivate" },
{ "$set": { "Info": "Active" } },
{ "new": true }
function (err, doc) {
if (err) { // err: any errors that occurred
console.log(err);
} else { // doc: the document before updates are applied if `new: false`
console.log(doc); // , the document returned after updates if `new true`
console.log(doc.Info);
}
}
);
};
above condtion matched and info getting changed but i want to delete VerificationCode,VerificationExpires some one help me out
exports.updatearticle = function(req, res) {
Article.findOne( { "Username":'xx', "Email":'xx#gmail.com', "Info": "Deactivate" }, function(err, result){
if (!err && result) {
result.Info = "Active"; // update ur values goes here
result.VerificationCode = "";
result.VerificationExpires = {};
var article = new Article(result);
article.save(function(err, result2){
if(!err) {
res.send(result2);
} else res.send(err);
})
} else res.send(err);
});
}
home this may help

auto-increment using loopback.js and MongoDB

i want to increase mongodb document number automatically using loopback.
I made function in mongo
function getNextSequence(name) {
var ret = db.counters.findAndModify(
{
query: { _id: name },
update: { $inc: { seq: 1 } },
new: true
}
);
return ret.seq;
}
db.tweet.insert(
{
"_id" : getNextSequence("userid"),
"content": "test",
"date": "1",
"ownerUsername": "1",
"ownerId": "1"
}
)
It is working in mongo shell.
However when I insert using loopback.js browser (http://localhost:3000/explorer/), It is not working.
400 error(SytaxError) code is showing.
I can not use mongo function in loopback rest API ?
I think problem is quotes in this line getNextSequence("userid"),
Create a collection counters with properties value and collection
{
"name": "counters",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"type": "number",
"collection": "string"
},
"validations": [],
"relations": {},
"acls": [
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
],
"methods": []
}
Now supposing your auto-increment collection name tweets.
Insert this value to counters.
{
"value" : 0,
"collection" : "tweet"
}
Now common/models/tweet.js
tweet.observe('before save', function (ctx, next) {
var app = ctx.Model.app;
//Apply this hooks for save operation only..
if(ctx.isNewInstance){
//suppose my datasource name is mongodb
var mongoDb = app.dataSources.mongodb;
var mongoConnector = app.dataSources.mongodb.connector;
mongoConnector.collection("counters").findAndModify({collection: 'tweet'}, [['_id','asc']], {$inc: { value: 1 }}, {new: true}, function(err, sequence) {
if(err) {
throw err;
} else {
// Do what I need to do with new incremented value sequence.value
//Save the tweet id with autoincrement..
ctx.instance.id = sequence.value.value;
next();
} //else
});
} //ctx.isNewInstance
else{
next();
}
}); //Observe before save..
I would love to add 1 more point to Robins Answer,you can add upsert:true so that it automatically creates the document if it doesn't exist
tweet.observe('before save', function (ctx, next) {
var app = ctx.Model.app;
//Apply this hooks for save operation only..
if(ctx.isNewInstance){
//suppose my datasource name is mongodb
var mongoDb = app.dataSources.mongodb;
var mongoConnector = app.dataSources.mongodb.connector;
mongoConnector.collection("counters").findAndModify({collection: 'tweet'}, [['_id','asc']], {$inc: { value: 1 }}, {new: true,upsert:true}, function(err, sequence) {
if(err) {
throw err;
} else {
// Do what I need to do with new incremented value sequence.value
//Save the tweet id with autoincrement..
ctx.instance.id = sequence.value.value;
next();
} //else
});
} //ctx.isNewInstance
else{
next();
}
}); //Observe before save..
You can do something like in this example for loopback 4
let last_record = await this.testRepository.findOne({order: ['id DESC']});
if(last_record) invoice.id = last_record.id+1;
This will generate your model with the property:
#property({
type: 'number',
id: true,
default: 1,
generated: false
})
id: number;
Hopefully, this helps, please write me if there is any other code. Thanks
If you want to use MongoDB operators directly in loopback methods you need to enable the option "allowExtendedOperators", you can do so on a per model basis or at the data source level (will apply to all models using the data source).
datasources.json:
"MongoDs": {
"host": "127.0.0.1",
"port": 27017,
"url": "mongodb://localUser:MYPASSWORD!#127.0.0.1:27017/test-database",
"database": "test-database",
"password": "MYPASSWORD!",
"name": "MongoDs",
"user": "localUser",
"useNewUrlParser": true,
"connector": "mongodb",
"allowExtendedOperators": true
},