I'm trying to create an api which will return search results which match more than one parameter. I can query one parameter fine at the moment.
Here is an example url
http://localhost:3000/api/search?term=javascript&impact=sdg1
I want the results to include both term=javascript AND impact=sdg1
import Cors from "cors";
import initMiddleware from "../../util/init-middleware";
import { connectToDatabase } from "../../util/mongodb";
const cors = initMiddleware(
Cors({
methods: ["GET", "POST", "OPTIONS"],
})
);
export default async function handler(req, res) {
await cors(req, res);
const { db } = await connectToDatabase();
const data = await db
.collection("jobs")
.aggregate([
{
$search: {
search: [
{
query: req.query.term,
path: ["title", "role"],
},
{
query: req.query.impact,
path: ["impact"],
},
],
},
},
])
.sort({ date: -1 })
.toArray();
res.json(data);
}
Is this possible and can anyone suggest the right sort of query to write?
Many thanks in advance
The way to accomplish this is with the compound operator. Here are the docs and here is how it would look in your code:
export default async function handler(req, res) {
await cors(req, res);
const { db } = await connectToDatabase();
const data = await db
.collection("jobs")
.aggregate([
{
$search: {
"compound": {
"must": [{
"text": {
"query": req.query.term,
"path": ["title", "role"],
}
}],
"filter":[{
"text": {
"query": req.query.impact,
"path": ["impact"],
}
}]
}
},
},
])
.sort({ date: -1 })
.toArray();
res.json(data);
}
Related
I am trying to update using this route.
router.put("/:id", async(req,res)=>{
try {
const updateUser = await User.findByIdAndUpdate(req.params.id, {
$push: {
clients:{
client_name: req.body.client_name,
client_Username: req.body.client_Username,
client_Password: req.body.client_Password,
documents : [
{
name : req.body.docName,
descritption : req.body.docDescription,
doc_upload : req.body.doc_upload,
}
]
}
}
},{new:true})
res.status(200).json(updateUser);
}
catch(err) {
res.status(500).json(err);
}
});
Once the function founds the id it updates client_name, client_Username and client_password without any issue.
My problem is when I try to update the nested array documents with a name/description and doc_upload. I am not able to do that.
What’s wrong ? How to do it please ?
One solution could be to separate the updates:
router.put('/:id', async (req, res) => {
try {
const { id } = req.params;
const { client_name, client_Username, client_Password } = req.body;
const updateUser = await User.findByIdAndUpdate(
id,
{
$push: {
clients: {
client_name,
client_Username,
client_Password,
},
},
},
{ new: true }
);
await User.findOneAndUpdate(
{
id,
'clients.client_name': client_name,
'clients.client_Username': client_Username,
},
{
$push: {
'clients.$.documents': {
name: req.body.docName,
descritption: req.body.docDescription,
doc_upload: req.body.doc_upload,
},
},
}
);
res.status(200).json(updateUser);
} catch (err) {
res.status(500).json(err);
}
});
Please can anyone tell me how can I get the amount variable or its data which I am fetching from req.body outside of the this function?
app.post("/pay", (req, res) => {
console.log(req.body);
const { amount , description , name } = req.body; //this is that amount variable
const create_payment_json = {
intent: "sale",
payer: {
payment_method: "paypal",
},
redirect_urls: {
return_url: "http://localhost:3000/success",
cancel_url: "http://localhost:3000/cancel",
},
transactions: [
{
item_list: {
items: [
{
name: name,
sku: "001",
price: amount,
currency: "USD",
quantity: 1,
},
],
},
amount: {
currency: "USD",
total: amount,
},
description: description,
},
],
};
paypal.payment.create(create_payment_json, function (error, payment) {
if (error) {
throw error;
} else {
for (let i = 0; i < payment.links.length; i++) {
if (payment.links[i].rel === "approval_url") {
res.redirect(payment.links[i].href);
}
}
}
});
});
app.get("/success", (req, res) => {
const payerId = req.query.PayerID;
const paymentId = req.query.paymentId;
const execute_payment_json = {
payer_id: payerId,
transactions: [
{
amount: {
currency: "USD",
total: amount, // I want it here also
},
},
],
};
paypal.payment.execute(
paymentId,
execute_payment_json,
function (error, payment) {
if (error) {
console.log(error.response);
;
} else {
console.log(JSON.stringify(payment));
res.send("Success");
}
}
);
});
It's very unclear from your question, but it seems like you just want to have access to amount from outside the response callback. If it is as plain as that, you just need to have a place for it in a higher scope. For example, I'm going to store all the payments in a payments array. I'm also renaming "ammount" to "amount" (it's misspelled).
Whenever a POST is made to app.post("/pay"), we push a payment. payments is available to app.get("/success") because it is in a higher scope.
If this isn't what you are trying to do, you need to add more details to your question and explain exactly what isn't working.
index.js
import express from "express";
const app = express();
const payments = [];
app.use(express.json());
app.get("/", (req, res) => {
res.send("Hello world");
});
app.get("/success", (req, res) => {
console.log(`There have been ${payments.length} payments`);
if (payments.length) {
const {person, amount, time} = payments[payments.length - 1];
console.log(`Last payment was ${amount} by ${person} # ${time}`);
}
res.sendStatus(200);
});
app.post("/pay", (req, res) => {
const {person, amount} = req.body;
const time = Date.now();
payments.push({person, amount, time});
console.log(`${person} paid ${amount} # ${time}`);
res.sendStatus(200);
});
app.listen(3002, () => {
console.log("Listening");
});
This is the file that I used to test with. It uses node-fetch as a fetch polyfill.
test.js
import fetch from "node-fetch";
const sleep = (t=1000) => new Promise(r => setTimeout(r, t));
const main = async () => {
const payResponse = await fetch("http://localhost:3002/pay", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
person: "Bob Barker",
amount: 500
})
});
await sleep();
const checkResponse = await fetch("http://localhost:3002/success");
};
main()
.then(() => console.log("Done"))
.catch(err => console.error(err));
Running it produces this:
Listening
Bob Barker paid 500 # 1631202912836
There have been 1 payments
Last payment was 500 by Bob Barker # 1631202912836
I am interested in how to create log table that writes data in own table, every time user makes some request.
And how to get data like this:
{
_id: ObjectId('4f442120eb03305789000000'),
host: "127.0.0.1",
logname: null,
user: 'frank',
time: ISODate("2000-10-10T20:55:36Z"),
path: "/apache_pb.gif",
request: "GET /apache_pb.gif HTTP/1.0",
status: 200,
response_size: 2326,
referrer: "[http://www.example.com/start.html](http://www.example.com/start.html)",
user_agent: "Mozilla/4.08 [en] (Win98; I ;Nav)"
}
Maybe not all of this data, but atleast who made the request, what type of request, path and time.
I am using nodejs, mongodb, mongoose.
You can write a middleware that logs all the requests, being sent to your server, to the MongoDB Database.
You can easily get the information you are looking for, using these npm packages,
1 - useragent
2 - express-useragent
I solved on this way.
My middlewere
const Log = require("../models/log");
const log = async (req, res, next) => {
try {
let user_id = req.user.id
let firstName = req.user.firstName
let method = req.method
let path = req.path
const log = new Log({ user_id, firstName, method, path });
try {
await log.save()
} catch (e) {
res.status(400).send(e)
}
next();
} catch (e) {
res.status(401).send(e);
}
};
module.exports = log;
Model
const mongoose = require('mongoose')
const logSchema = new mongoose.Schema({
user_id: {
type: String,
},
firstName: {
type: String,
},
method: {
type: String,
},
path: {
type: String,
},
}, {
timestamps: true
})
const Log = mongoose.model('Log', logSchema);
module.exports = Log;
and router
const express = require('express')
const Log = require('../models/log')
const auth = require('../middleware/auth')
const router = new express.Router()
//Create log
router.post('/logs', async (req, res) => {
const log = new Log({
...req.body
})
try {
await log.save()
res.status(201).send(log)
} catch (e) {
res.status(400).send(e)
}
})
//Sort and search
router.get('/logs', auth, async (req, res) => {
const match = {}
const sort = {}
if (req.query.completed) {
match.completed = req.query.completed === 'true'
}
if (req.query.sortBy) {
const parts = req.query.sortBy.split(':')
sort[parts[0]] = parts[1] === 'desc' ? -1 : 1
}
try {
await req.user.populate({
path: 'logs',
match,
options: {
limit: parseInt(req.query.limit),
skip: parseInt(req.query.skip),
sort
}
}).execPopulate()
res.send(req.user.logs)
} catch (e) {
res.status(500).send()
}
})
module.exports = router;
This is the model for course and topic, I want to populate topic in course with the help of mongoose. When we call API I want a joint result of course and topic.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
let courseSchema = new Schema({
course_id: {
type: Number
},
course_title: {
type: String
},
course_description: {
type: String
},
course_duration:{
type: Number
},
topic:{
type: mongoose.Schema.Types.ObjectId,
ref: "Topic"
}
}, {
collection: "courses"
})
let topicSchema = new Schema({
topic_id: {
type: Number
},
topic_title: {
type: String
},
topic_description: {
type: String
}
}
,{
collection: "topics"
})
const Topic = mongoose.model("Topic", topicSchema)
const Course = mongoose.model('Course', courseSchema)
module.exports = { Topic, Course };
This is API for GET, and I use populate as well but not able to get the joint result of course and topic.
let mongoose = require('mongoose'),
express = require('express'),
router = express.Router();
var { Topic, Course }= require('../models/Course')
router.route('/').get((req, res) => {
Course.find().populate('topic').exec((error, data) => {
if (error) {
return next(error)
} else {
res.json(data)
}
})
})
I want output like this:
{
"_id": "5fea9d7cd6651122e04ce5ed",
"course_id": 2,
"course_title": "GOlang",
"course_description": "google ",
"course_duration": 11,
"topic_id": 3,
"topic_title": "hoisting",
"topic_description": "variable and function",
"__v": 0
}
Whay did you do that ?
router.route('/').get((req, res) => {
Course.find().populate('topic').exec((error, data) => {
if (error) {
return next(error)
} else {
res.json(data)
}
})
})
and not this instead ?
router.get('/',(req, res) => {
Course.find().populate('topic').exec((error, data) => {
if (error) {
return next(error)
} else {
res.json(data)
}
})
})
I want to load only the UserData which belongs to the correct AdminId
In this Code you load all the UserData. It works fine
async mounted() {
this.userData = (await DataService.index()).data;
}
Now i want to give the AdminId to my backend. This is my Code which does not work.
async mounted() {
this.userData = (await DataService.index({ AdminId: this.$store.state.admin.id })).data;
}
This is my Backend: The Code works for where :{AdminId: 1}
async index(req, res) {
try {
const { AdminId } = req.body
const userData = await User.findAll({
where: { AdminId: AdminId },
include: [UserStatus,
{ model: SurveyResult, include: [Survey] }]
})
.map(user => user.toJSON())
}
}
Change to req.query works
async index (req, res) {
try {
const { adminId } = req.query
const userData = await User.findAll({
where: { AdminId: adminId },
include: [UserStatus,
{ model: SurveyResult, include: [Survey] }]
})
.map(user => user.toJSON())
res.send(userData)
} catch (err) {
console.log(err)
}