Approach to selecting a document - javascript

I am using Couchbase in a node app. Every time I insert a document, I am using a random UUID.
It inserts fine and I could retrieve data based on this id.
But in reality, I actually want to search by a key called url in the document. To be able to get or update or delete a document.
I could possibly add the url as the id I suppose but that is not what I see in any database concepts. Ids are not urls
or any unique names. They are typically random numbers or incremental numbers.
How could I approach this so that I can use a random UUID as id but be able to search by url?
Cos lets say the id was 56475-asdf-7856, I am not going to know this value to search for right.
Whereas if the id was https://www.example.com I know about this url and searching for it would give me what I want.
Is it a good idea making the url the id.
This is in a node app using Couchbase.
databaseRouter.put('/update/:id', (req, res) => {
updateDocument(req)
.then(({ document, error }) => {
if (error) {
res.status(404).send(error);
}
res.json(document);
})
.catch(error => res.status(500).send(error));
});
export const updateDocument = async (req) => {
try {
const result = await collection.get(req.params.id); // Feels like id should be the way to do this, but doesn't make sense cos I won't know the id beforehand.
document.url = req.body.url || document.url;
await collection.replace(req.params.id, document);
return { document };
} catch (error) {
return { error };
}
};

I think it's okay to use URLs as IDs, especially if that's the primary way you're going to lookup documents, and you don't need to change the URL later. Yes, often times IDs are numbers or UUIDs, but there is no reason you have to be restricted to this.
However, another approach you can take is to use a SQL query (SQL++, technically, since this is a JSON database).
Something like:
SELECT d.*
FROM mybucket.myscope.mydocuments d
WHERE d.url = 'http://example.com/foo/baz/bar'
You'll also need an index with that, something like:
CREATE INDEX ix_url ON mybucket.myscope.mydocuments (url)
I'd recommend checking out the docs for writing a SQL++ query (sometimes still known as "N1QL") with Node.js: https://docs.couchbase.com/nodejs-sdk/current/howtos/n1ql-queries-with-sdk.html
Here's the first example in the docs:
async function queryPlaceholders() {
const query = `
SELECT airportname, city FROM \`travel-sample\`.inventory.airport
WHERE city=$1
`;
const options = { parameters: ['San Jose'] }
try {
let result = await cluster.query(query, options)
console.log("Result:", result)
return result
} catch (error) {
console.error('Query failed: ', error)
}
}

Related

Using Lambda with Nodejs Count Some queries in Dynamo DB

After using the below to pull data from Dynamo db sucessfully
async function pullone(sessionid) {
const params = {
TableName: dynamodbTableName,
Key: {
'sessionid': sessionid
}
};
return await dynamodb.get(params).promise().then((response) => {
return response.Item
}, (error) => {
console.error('Do your custom error handling here. I am just gonna log it: ', error);
});
}
Instead of 'return response.Item' i just want to return the count instead.
I tried doing count(pullone(sessionid)) but not sure if that is even a valid method. Please assist
Not sure if I understood your question, but:
Since you're requesting data associated with a primary key, you'll get either 0 or 1 element in Item.
So, if you aim to know if "you've found something or not", you can use Number(response.Item != null) and you'll get 1 in case of "something" and 0 in case of "nothing".
If, instead, your data contains a "count" attribute, then (await pullone(sessionId)).count should work.
Otherwise, you have to query your DB (but you'll get Items (plural) in your response) and use the length() function of the Items array you'll get in the response.

getProduct with id from api, error 400, undefined and bad request

getProduct: async ({commit}, id) => {
const res = await axios.get('https://localhost:44394/api/Products/' + id)
commit('GET_PRODUCT', res.data)
},
this code doesnt work and it doesnt get the specific product, but if I do like this...
getProduct: async ({commit}) => {
const res = await axios.get('https://localhost:44394/api/Products/2')
commit('GET_PRODUCT', res.data)
},
and put a specific id in the link (2 in this case) it works for the product with id 2. How do i get it to get every product from its own id?
Check your id is integer and have right id.
call method getProduct(1)
if you didn't got 400 error, it is your id have problem, not the getProduction function.
Maybe you can try https://localhost:44394/api/Products/${id}
And you better set up 1 file that store the constant for URL, like
apiCallUrl.js
and set the const URL = https://localhost:44394/
It'll cleaner for later when your code is bigger, and whenever you want to change the API, you just need to go to there.

Mongoose Update document

I am using Node.js and mongoose Module, I am looking for a way to count how many documents a user has and then if they have more then 0 documents it would edit their existing document and add the input so at the end it would have the previous text + the text that the user sent, so far this is how much I gotten.
const List = require('../Models/list.js')
List.countDocuments({}, function(err, count) {
if(count>0){
//edit document
}
else if(count=0){
const input = List.create({
User: User.name,
Songlist: args[0],
})
}
})
console.log('done')
here is how I think the code would look like
List.update(User.name) => update Songlist into List.Songlist + '|' + args[0]
I have never seen an update method like that. I am a nodejs developer. well, maybe there's a way like that.
Here's how I do to update a document
await Product.findByIdAndUpdate(id, //here where I have written "id" you have to write the id of the document you want to update.
{ //here in this object you have to put the variables of updated values
title: title,
description:description,
product_id:product_id,
category,
price,
});
there is also another method
await Product.findOneAndUpdate(name: 'asim', //let's suppose
{ //updated values
title:title,product: product
})
you can also read the documentation here https://mongoosejs.com/docs/tutorials/findoneandupdate.html

How to crawling using Node.js

I can't believe that I'm asking an obvious question, but I still get the wrong in console log.
Console shows crawl like "[]" in the site, but I've checked at least 10 times for typos. Anyways, here's the javascript code.
I want to crawl in the site.
This is the kangnam.js file :
const axios = require('axios');
const cheerio = require('cheerio');
const log = console.log;
const getHTML = async () => {
try {
return await axios.get('https://web.kangnam.ac.kr', {
headers: {
Accept: 'text/html'
}
});
} catch (error) {
console.log(error);
}
};
getHTML()
.then(html => {
let ulList = [];
const $ = cheerio.load(html.data);
const $allNotices = $("ul.tab_listl div.list_txt");
$allNotices.each(function(idx, element) {
ulList[idx] = {
title : $(this).find("list_txt title").text(),
url : $(this).find("list_txt a").attr('href')
};
});
const data = ulList.filter(n => n.title);
return data;
}). then(res => log(res));
I've checked and revised at least 10 times
Yet, Js still throws this result :
root#goorm:/workspace/web_platform_test/myapp/kangnamCrawling(master)# node kangnam.js
[]
Mate, I think the issue is you're parsing it incorrectly.
$allNotices.each(function(idx, element) {
ulList[idx] = {
title : $(this).find("list_txt title").text(),
url : $(this).find("list_txt a").attr('href')
};
});
The data that you're trying to parse for is located within the first index of the $(this) array, which is really just storing a DOM Node. As to why the DOM stores Nodes this way, it's most likely due to efficiency and effectiveness. But all the data that you're looking for is contained within this Node object. However, the find() is superficial and only checks the indexes of an array for the conditions you supplied, which is a string search. The $(this) array only contains a Node, not a string, so when you you call .find() for a string, it will always return undefined.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
You need to first access the initial index and do property accessors on the Node. You also don't need to use $(this) since you're already given the same exact data with the element parameter. It's also more efficient to just use element since you've already been given the data you need to work with.
$allNotices.each(function(idx, element) {
ulList[idx] = {
title : element.children[0].attribs.title,
url : element.children[0].attribs.href
};
});
This should now populate your data array correctly. You should always analyze the data structures you're parsing for since that's the only way you can correctly parse them.
Anyways, I hope I solved your problem!

node-postgres dynamic query

I am building a REACT note taking app.
I only track the changes the user makes to the note, and not what the current state of the note is.
If there are no changes to a specific property, the property will be sent as an empty string.
I am handling this in NODE (node-postgres) with the following function:
const updateNote = async (req, res) => {
const { category, title, body, nid } = req.body;
let noteStatement = "";
let valueStatement = "";
for (const key in req.body)
{
if (req.body[key] !== "" && key !== "nid") {
noteStatement = noteStatement + key + ", ";
valueStatement = valueStatement + `'${req.body[key]}', `;
}
}
try {
const result = await pool.query(
`UPDATE notes SET (${noteStatement}last_updated)
= (${valueStatement}(to_timestamp(${Date.now()} / 1000.0)))
WHERE nid = ${nid} RETURNING *`
);
const note = result.rows;
return res.status(200).send({ note });
} catch (err) {
return res.send({error: err});
}
};
I may be overthinking, but the goal was to send the smallest bit of data to the DB as possible.
I have spent a fair amount of time on this and this is the most pragmatic approach I came up with.
Is writing this type of query bad practice?
Would it make more sense to send all the note data including properties that have not been updated from React and have a fixed query updating all properties?
EDIT: Updated Query
const updateNote = async (req, res) => {
const { category, title, body, nid } = req.body;
const text = `UPDATE notes SET (category, title, body, last_updated)
= ($1, $2, $3, (to_timestamp(${Date.now()} / 1000.0)))
WHERE nid = $4 RETURNING *`;
const values = [category, title, body, nid];
try {
const result = await pool.query(text, values);
const note = result.rows;
return res.status(200).send({ note });
} catch (err) {
return res.send({ error: err });
}
};
I wanted to leave a comment but soon realized I approach the character limit so I would just leave it as a response.
First of, I want to make sure I understand what you are trying to accomplish. I assume you just wanna update your DB with only the fields that has been provided from the client. With that in mind I just want to underline the fact that most people are trying to overcomplicate things that should not. Everything in software is a tradeoff, in your case your data isn't that big to worry about updating just certain fields. It can be done but not the way you are doing it right now, you can have a utility function that would build a parameterized query based on the values that are not empty/null depending on how would you send the data that did not change from the client
Which brings me to the 2nd thing, you should never write a SQL query the way you have done it, by concatonating a string, leaves you vulnerable to SQL injections. Instead you must always use parameterized query unless you use some kind of library that abstracts writing the queries (ORMs).
As a sidenote, never trust data that comes from the client, so always, always validate the data on the server before you make any changes to the DB, even if you already did validation on the client. You can do it using a middleware like celebrate or other validation libraries. Never trust anything that comes from the client.

Categories