I am creating routers using koa. We have declared two routers as shown below.
app.get('/order/:id', async ctx => {
const { id } = ctx.params;
try {
const data = await order.findOne({
where: { order_id: id }
});
ctx.body = data;
} catch (e) {
ctx.body = e.message;
}
});
app.get('/order/customer', async ctx => {
const { id } = ctx.request.user;
try {
const data = await order.findOne({
where: { customer_id: id }
});
ctx.body = data;
} catch (e) {
ctx.body = e.message;
}
});
The first is a query that selects an order by order_id, and the second is a query that selects the order of the user with an id authenticated by the middleware.
curl http://localhost:3000/order/1
The order_id is 1 when I type in the above.
curl http://localhost:3000/order/customer
However, unlike my intention, when I enter the above, and check the query, the order_id is called customer. Is there any way I can make url simple to make /order/customer available?
If you have any questions I'm missing from the question or if you can help me, please comment or reply.
You're having the issue with order of routes definitions. You should have specific path route first and dynamic route later. Here, dynamic route I meant for /:id:
'/order/customer' // first
'/order/:id' // later
Related
I've been learning the mern stack from this book
I'm now on Nested Routes under React Router chapter
The web application is supposed to render this on the page.
When clicking the Select link under the Action column, the description of
an issue is displayed on the bottom part of the page.
But in my case, this thing happens:
and at the same time this error is being thrown in the console:
The only time the web application runs properly is when I downgraded the
graphql version to 0.13.2 (this is the version the book uses).
The thing is I try to use up to date versions of the project dependencies
as much as possible. There has never been much trouble as I follow the book
until I got into this.
I don't understand, why is this error being thrown when I use a more up to
date version of the graphql over the old version?
(I use graphql version 15.8.0 and apollo-server-express version 2.25.4)
I tried to modify the .jsx file that renders the description data
on the page.
async loadData() {
const { match: { params: { id } } } = this.props;
//I tried to parse the id to make it an int type before getting it into
//the graphql query
id = parseInt(id); // this is the thing that I've added
const query = `query issue($id: Int!) {
issue (id: $id) {
id description
}
}`;
const data = await graphQLFetch(query, { id });
if (data) {
this.setState({ issue: data.issue });
} else {
this.setState({ issue: {} });
}
}
This is the codes graphQLFetch function
const dateRegex = new RegExp('^\\d\\d\\d\\d-\\d\\d-\\d\\d');
function jsonDateReviver(key, value) {
if (dateRegex.test(value)) return new Date(value);
return value;
}
async function graphQLFetch(query, variables = {}) {
try {
const response = await fetch(window.ENV.UI_API_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, variables }),
});
const body = await response.text();
const result = JSON.parse(body, jsonDateReviver);
if (result.errors) {
const error = result.errors[0];
if (error.extensions.code === 'BAD_USER_INPUT') {
const details = error.extensions.exception.errors.join('\n');
alert(`${error.message}:\n ${details}`);
} else {
alert(`${error.extensions.code}: ${error.message}`);
}
}
return result.data;
} catch (e) {
alert(`Error in sending data to server: ${e.message}`);
return null;
}
}
When I did this, it doesn't throw any error anymore but it doesn't render
the description data on the page either.
Can someone please help me with this?? Thanks in advance...
Sorry If I'm not explaining this very well. I'm trying to delete from a database using this button press, but whenever I try to delete it will only delete the first item in the database. I'm pretty sure there's something wrong with the ID I'm getting. Can anyone spot any obvious issues I'm missing here?
Button Press:
tasksDOM.addEventListener('click', async (e) => {
const el = e.target
if (el.parentElement.classList.contains('delete-btn')) {
loadingDOM.style.visibility = 'visible'
const id = el.parentElement.dataset.id
try {
await axios.delete(`/tm/v1/tasks/${id}`)
showTasks()
} catch (error) {
console.log(error)
}
}
loadingDOM.style.visibility = 'hidden'
})
Delete:
app.delete("/tm/v1/tasks/:id", async (req, res) => {
try {
const id = req.params.id;
const response = await Task.findOneAndDelete({ id });
res.status(200).json({ msg: 'deleted' });
} catch (error) {
res.status(500).json({ msg: error });
};
});
Two solutions -
1. const response = await Task.findByIdAndDelete(id);
2. const response = await Task.findOneAndDelete({ _id : mongoose.Types.ObjectId(id) });
Don't forget to import mongoose for second method.
Explanation -
In your code findOneAndDelete is taking id as argument which doesn't exist for mongoose so default, its deleting the first entry so you need to use _id here. Second thing is, id param is string type and _id is ObjectId so it will not match. To match this, you need to convert this string value to mongoose ObjectId.
findByIdAndDelete works with string value as well!
I tried to find the solutions over here but unable to get success while using $pull as the array values I have does not contain `mongo_id'.
So the scenario is that , I am trying to delete the specific comment of the particular user which I am passing through query params. M
My mongo data looks like this:
Now I am making API Delete request like this : http://localhost:8000/api/articles/learn-react/delete-comment?q=1 on my localhost .
ANd finally my code looks like this:
import express from "express";
import bodyParser from "body-parser";
import { MongoClient } from "MongoDB";
const withDB = async (operations, res) => {
try {
const client = await MongoClient.connect(
"mongodb://localhost:27017",
{ useNewUrlParser: true },
{ useUnifiedTopology: true }
);
const db = client.db("my-blog");
await operations(db);
client.close();
} catch (error) {
res.status(500).json({ message: "Error connecting to db", error });
}
};
app.delete("/api/articles/:name/delete-comment", (req, res) => {
const articleName = req.params.name;
const commentIndex = req.query.q;
withDB(async(db) => {
try{
const articleInfo = await db.collection('articles').findOne({name:articleName});
let articleAllComment = articleInfo.comments;
console.log("before =",articleAllComment)
const commentToBeDeleted = articleInfo.comments[commentIndex];
//console.log(commentToBeDeleted)
// articleAllComment.update({
// $pull: { 'comments':{username: commentToBeDeleted.username }}
// });
articleAllComment = articleAllComment.filter( (item) => item != commentToBeDeleted );
await articleAllComment.save();
console.log("after - ",articleAllComment);
//yaha per index chahiye per kaise milega pta nhi?
//articleInfo.comments = gives artcle comment
res.status(200).send(articleAllComment);
}
catch(err)
{
res.status(500).send("Error occurred")
}
},res);
});
I have used the filter function but it is not showing any error in terminal but also getting 500 status at postman.
Unable to figure out the error?
I believe you'll find a good answer here:
https://stackoverflow.com/a/4588909/9951599
Something to consider...
You can use MongoDB's built-in projection methods to simplify your code.
https://docs.mongodb.com/manual/reference/operator/projection/positional/#mongodb-projection-proj.-
By assigning a "unique ID" to each of your comments, you can find/modify the comment quickly using an update command instead of pulling out the comment by order in the array. This is more efficient, and much simpler. Plus, multiple read/writes at once won't interfere with this logic during busy times, ensuring that you're always deleting the right comment.
Solution #1: The recommended way, with atomic operators
Here is how you can let MongoDB pull it for you if you give each of your comments an ID.
await db.collection('articles').updateOne({ name:articleName },
{
$pull:{ "comments.id":commentID }
});
// Or
await db.collection('articles').updateOne({ name:articleName, "comments.id":commentID },
{
$unset:{ "comments.$":0 }
});
Solution #2 - Not recommended
Alternatively, you could remove it by index:
// I'm using "3" here staticly, put the index of your comment there instead.
db.collection('articles').updateOne({ name:articleName }, {
$unset : { "comments.3":0 }
})
I do not know why your filter is erroring, but I would recommend bypassing the filter altogether and try to utilize MongoDB's atomic system for you.
I have the following user defined role in security with a predicate function on the create for a collection called formEntryData. Now I can create if I don't have the function which is below.
Under the Create function option
Lambda("values", Equals(Identity(), Select(["data"], Var("values"))))
Now I am creating a request with the following code, which works when the create is just set to all via checking the box, but if I use the function above it fails with permission denied. I must be doing somethign wrong
import { query as q } from "faunadb";
import { serverClient } from "../../utils/fauna-auth";
import { authClient } from "../../utils/fauna-auth";
import { getAuthCookie } from "../../utils/auth-cookies";
export default async (req, res) => {
// const { firstName, lastName, telephone, creditCardNumber } = req.body;
const token = getAuthCookie(req);
console.log(token);
const data = req.body.data;
var element = req.body.data;
element["FormID"] = req.body.id;
try {
await authClient(token).query(
q.Create(q.Collection("FormEntryData"), {
data: element,
})
);
res.status(200).end();
} catch (e) {
res.status(500).json({ error: e.message });
}
};
Any help would be greatly appreciated.
UPDATE: I have also added a index for the collection and given it read permissions in the Role
This was also asked on the Fauna community forums: https://forums.fauna.com/t/roles-membership-auth-token-permissions-denied/1681/4
It looks like two things were needed:
update the create predicate to match the data.user field: Lambda("values", Equals(CurrentIdentity(), Select(["data", "user"], Var("values")))), and
a user field needs to be provided in order to pass the provided predicate.
The answer in the forums used two requests: One to retrieve the calling user document (with CurrentIdentity()), and another to create the FormEntryData document. This can be (should be) done with a single request to limit cost (Every request to Fauna will take at least one Transactional Compute Op), and of course network time for two round trips. Consider the following:
await authClient(token).query(
Let(
{
userRef: q.CurrentIdentity(),
},
q.Create(q.Collection("FormEntryData"), {
data: {
...element,
user: q.Var("userRef")
}
})
)
);
I use NodeJS to insert documents in MongoDB. Using collection.insert I can insert a document into database like in this code:
// ...
collection.insert(objectToInsert, function(err){
if (err) return;
// Object inserted successfully.
var objectId; // = ???
});
// ...
How can I get the _id of inserted object?
Is there any way to get the _id without getting latest object inserted _id?
Supposing that in same time a lot of people access the database, I can't be sure that the latest id is the id of object inserted.
A shorter way than using second parameter for the callback of collection.insert would be using objectToInsert._id that returns the _id (inside of the callback function, supposing it was a successful operation).
The Mongo driver for NodeJS appends the _id field to the original object reference, so it's easy to get the inserted id using the original object:
collection.insert(objectToInsert, function(err){
if (err) return;
// Object inserted successfully.
var objectId = objectToInsert._id; // this will return the id of object inserted
});
There is a second parameter for the callback for collection.insert that will return the doc or docs inserted, which should have _ids.
Try:
collection.insert(objectToInsert, function(err,docsInserted){
console.log(docsInserted);
});
and check the console to see what I mean.
As ktretyak said, to get inserted document's ID best way is to use insertedId property on result object. In my case result._id didn't work so I had to use following:
db.collection("collection-name")
.insertOne(document)
.then(result => {
console.log(result.insertedId);
})
.catch(err => {
// handle error
});
It's the same thing if you use callbacks.
I actually did a console.log() for the second parameter in the callback function for insert. There is actually a lot of information returned apart from the inserted object itself. So the code below explains how you can access it's id.
collection.insert(objToInsert, function (err, result){
if(err)console.log(err);
else {
console.log(result["ops"][0]["_id"]);
// The above statement will output the id of the
// inserted object
}
});
if you want to take "_id" use simpley
result.insertedId.toString()
// toString will convert from hex
Mongo sends the complete document as a callbackobject so you can simply get it from there only.
for example
collection.save(function(err,room){
var newRoomId = room._id;
});
You could use async functions to get _id field automatically without manipulating data object:
async function save() {
const data = {
name: "John"
}
await db.collection('users').insertOne(data)
return data
}
Returns (data object):
{
_id: '5dbff150b407cc129ab571ca',
name: 'John',
}
Now you can use insertOne method and in promise's result.insertedId
#JSideris, sample code for getting insertedId.
db.collection(COLLECTION).insertOne(data, (err, result) => {
if (err)
return err;
else
return result.insertedId;
});
Similar to other responses, you can grab the variable using async await, es6+ features.
const insertData = async (data) => {
const { ops } = await db.collection('collection').insertOne(data)
console.log(ops[0]._id)
}
Another way to do it in async function :
const express = require('express')
const path = require('path')
const db = require(path.join(__dirname, '../database/config')).db;
const router = express.Router()
// Create.R.U.D
router.post('/new-order', async function (req, res, next) {
// security check
if (Object.keys(req.body).length === 0) {
res.status(404).send({
msg: "Error",
code: 404
});
return;
}
try {
// operations
let orderNumber = await db.collection('orders').countDocuments()
let number = orderNumber + 1
let order = {
number: number,
customer: req.body.customer,
products: req.body.products,
totalProducts: req.body.totalProducts,
totalCost: req.body.totalCost,
type: req.body.type,
time: req.body.time,
date: req.body.date,
timeStamp: Date.now(),
}
if (req.body.direction) {
order.direction = req.body.direction
}
if (req.body.specialRequests) {
order.specialRequests = req.body.specialRequests
}
// Here newOrder will store some informations in result of this process.
// You can find the inserted id and some informations there too.
let newOrder = await db.collection('orders').insertOne({...order})
if (newOrder) {
// MARK: Server response
res.status(201).send({
msg: `Order N°${number} created : id[${newOrder.insertedId}]`,
code: 201
});
} else {
// MARK: Server response
res.status(404).send({
msg: `Order N°${number} not created`,
code: 404
});
}
} catch (e) {
print(e)
return
}
})
// C.Read.U.D
// C.R.Update.D
// C.R.U.Delete
module.exports = router;