Cosmos DB query with JavaScript API v2 query for 1 doc - javascript

I have an async call chain that looks like this:
getConnections()
.then(() => addOneNewDoc())
.then(() => fetchOneDoc());
The addNewDoc() works fine and inserts a document. I then use the query capabilities of the API to query for the document in fetchOneDoc().
The call to fetch doc always returns undefined, but I can go see the document in the portal db browser. I've tried sleeping between the calls in case the doc just didn't make it in before the query, but that didn't work either.
const query = `select * from items i where i.id = '${docId}'`;
const {result: doc} = await connection.container.items.query(query);
if (!doc) {
console.log('GOT NO DOCS BACK');
return;
}
I have validated the query works fine in the portal.

Please refer to my sample code:
const cosmos = require('#azure/cosmos');
const CosmosClient = cosmos.CosmosClient;
const endpoint = "https://***.documents.azure.com:443/"; // Add your endpoint
const masterKey = "***"; // Add the masterkey of the endpoint
const client = new CosmosClient({ endpoint, auth: { masterKey } });
const databaseId = "db";
const containerId = "coll";
async function run() {
await insertItem();
}
async function insertItem(continuationToken) {
const { container, database } = await init();
const documentDefinition = { content: 'Hello World!' };
const { body } = await container.items.create(documentDefinition);
console.log('Created item with content: ', body.id);
return await queryItems1(body.id);
}
async function queryItems1(idParam) {
const { container, database } = await init();
const querySpec = {
query: "SELECT r.id,r._ts FROM root r where r.id = '"+ idParam +"'"
};
const queryIterator = await container.items.query(querySpec,null);
if (queryIterator.hasMoreResults()) {
const { result: results, headers } = await queryIterator.executeNext();
console.log(results)
}
}
async function init() {
const { database } = await client.databases.createIfNotExists({ id: databaseId });
const { container } = await database.containers.createIfNotExists({ id: containerId });
return { database, container };
}
run().catch(err => {
console.error(err);
});

Related

Code works fine when value is hardcoded, but fails when value is dynamic

I'm working on a chrome extension that grabs data from Rate My Professor's GraphQL API and then puts that rating on my universities courses portal. Here's my code:
background.js
const {GraphQLClient, gql} = require('graphql-request');
console.log("background.js loaded");
const searchTeacherQuery = gql`
query NewSearchTeachersQuery($text: String!, $schoolID: ID!)
{
newSearch {
teachers(query: {text: $text, schoolID: $schoolID}) {
edges {
cursor
node {
id
firstName
lastName
school {
name
id
}
}
}
}
}
}
`;
const getTeacherQuery = gql`
query TeacherRatingsPageQuery(
$id: ID!
) {
node(id: $id) {
... on Teacher {
id
firstName
lastName
school {
name
id
city
state
}
avgDifficulty
avgRating
department
numRatings
legacyId
wouldTakeAgainPercent
}
id
}
}
`;
const AUTH_TOKEN = 'dGVzdDp0ZXN0';
const client = new GraphQLClient('https://www.ratemyprofessors.com/graphql', {
headers: {
authorization: `Basic ${AUTH_TOKEN}`
}
});
const searchTeacher = async (professorName, schoolID) => {
console.log("searchTeacher called");
console.log(professorName);
console.log(typeof professorName);
console.log(schoolID);
const response = await client.request(searchTeacherQuery, {
text: professorName,
schoolID
});
if (response.newSearch.teachers === null) {
return [];
}
return response.newSearch.teachers.edges.map((edge) => edge.node);
};
const getTeacher = async (id) => {
const response = await client.request(getTeacherQuery, {id});
return response.node;
};
async function getAvgRating(professorName) {
console.log('1: ', professorName);
const teachers = await searchTeacher(professorName, 'U2Nob29sLTE0OTU=');
console.log(teachers);
const teacherID = teachers[0].id;
const teacher = await getTeacher(teacherID);
const avgRating = teacher.avgRating;
console.log(teacher);
console.log(avgRating);
return avgRating;
}
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
console.log('received message from content script:', request);
console.log('test:', request.professorName);
getAvgRating(request.professorName).then(response => {
sendResponse(response);
});
return true;
});
and here's content.js:
const professorLinks = document.querySelectorAll('td[width="15%"] a');
professorLinks.forEach(link => {
const professorName = link.textContent;
console.log(professorName);
chrome.runtime.sendMessage({ professorName }, (response) => {
console.log(response);
if (response.error) {
link.insertAdjacentHTML('afterend', `<div>Error: ${response.error}</div>`);
} else {
link.insertAdjacentHTML('afterend', `<div>${response}/5</div>`);
}
});
});
Now, if I set professorName to a fixed value, like this:
async function getAvgRating(professorName) {
const teachers = await searchTeacher('Hossein Kassiri', 'U2Nob29sLTE0OTU=');
console.log(teachers);
const teacherID = teachers[0].id;
const teacher = await getTeacher(teacherID);
const avgRating = teacher.avgRating;
console.log(teacher);
console.log(avgRating);
return avgRating;
}
the code works as intended, with the expected output:
but if searchTeacher is called with professorName instead of a fixed value like this:
async function getAvgRating(professorName) {
const teachers = await searchTeacher(professorName, 'U2Nob29sLTE0OTU=');
console.log(teachers);
const teacherID = teachers[0].id;
const teacher = await getTeacher(teacherID);
const avgRating = teacher.avgRating;
console.log(teacher);
console.log(avgRating);
return avgRating;
}
it returns an empty object:
dynamic graphql request vs hardcoded graphql request
i'm not sure if i'm missing something trivial, as the values being passed to searchTeacher appear to be exactly the same, but it only works when hardcoded. please let me know if i'm missing something, thank you.
After much troubleshooting, I found the issue. #Damzaky was correct, using the localeCompare method I was able to determine that the string from the HTML and my hardcoded string were not the same, was localeCompare would return -1. I cleansed the string from the HTML using this line of code:
const normalizedName = name.normalize('NFKD');
and passed that to searchTeacher, and now the behaviour is as expected. Thanks to everyone that helped.

Firebase Cloud Functions Async

I am making a function for firebase cloud functions, I want a function to be called every time a new document is created in "posts". I want this function to perform the tasks that I put inside the "onCeatePost" function.
The problem I have is that I'm not sure if this is the correct way to structure such a function.
In several firebase examples I have seen that it is always called return _; or return null; at the end of a task, but I don't know how to structure the function so that all the tasks are carried out, could someone help me to restructure my function or tell me what is wrong please.
There are several if statements in the function, if the created publication does not comply with them, I would like it to skip them but continue with the other tasks that I put inside the function.
I don't know if it's too much to ask, but I'm new to this language and I haven't been able to find the answer I'm looking for. Thank you!
exports.onPostCreate = functions.firestore.document("/posts/{postId}").onCreate(async (snap) => {
const post = snap.data();
if (post) {
try {
const topic = post.topic;
const contentForFeed = post.contentForFeed;
const uid = post.uid;
const previous = post.prev;
await db.collection("users").doc(uid).update({"stats.posts": admin.firestore.FieldValue.increment(1)});
if (topic) {
await db.collection("topics").doc(topic.id).collection("user-authors").doc(uid).set({"date": snap.createTime});
}
if (contentForFeed == true) {
const userPath = db.collection("users").doc(uid);
await userPath.update({"stats.lastUpdate": snap.createTime});
}
if (previous) {
const previousId = previous.id;
const previousUid = previous.uid;
const refPrev = db.collection("posts").doc(previousId);
await db.runTransaction(async (t) => {
const doc = await t.get(refPrev);
const priority = doc.data().stats.date;
const newDate = new admin.firestore.Timestamp(priority.seconds + 120, priority.nanoseconds);
await db.collection("posts").doc(previousId).update({"newDate": newDate});
});
if (previousUid != uid) {
const path = db.collection("users").doc(uid).collection("user-posts");
const dataToSet = {"timestamp": snap.createTime, "uid": uid, "postId": onReplyToPostId};
await path(dataToSet);
}
}
} catch (err) {
functions.logger.log(err);
}
} else {
return null;
}
});
You'll find below the adapted code (untested) with 4 corrections.
Here are explanations for the two most important ones:
(Correction 2) In a transaction you need to use the transaction's update() method and not the "standard one"
(Correction 4) When all the asynchronous work is complete you need to return a value or a Promise. See this documntation page for more details.
exports.onPostCreate = functions.firestore
.document('/posts/{postId}')
.onCreate(async (snap) => {
const post = snap.data();
if (post) {
try {
const topic = post.topic;
const contentForFeed = post.contentForFeed;
const uid = post.uid;
const previous = post.prev;
await db
.collection('users')
.doc(uid)
.update({
'stats.posts': admin.firestore.FieldValue.increment(1),
});
if (topic) {
await db
.collection('topics')
.doc(topic.id)
.collection('user-authors')
.doc(uid)
.set({ date: snap.createTime });
}
if (contentForFeed == true) {
const userPath = db.collection('users').doc(uid);
await userPath.update({ 'stats.lastUpdate': snap.createTime });
}
let previousUid; // <= Correction 1
if (previous) {
const previousId = previous.id;
previousUid = previous.uid; // <= Correction 1
const refPrev = db.collection('posts').doc(previousId);
await db.runTransaction(async (t) => {
const doc = await t.get(refPrev);
const priority = doc.data().stats.date;
const newDate = new admin.firestore.Timestamp(
priority.seconds + 120,
priority.nanoseconds
);
t.update(refPrev, { newDate: newDate }); // <= Correction 2
});
if (previousUid != uid) {
const path = db
.collection('users')
.doc(uid)
.collection('user-posts');
const dataToSet = {
timestamp: snap.createTime,
uid: uid,
postId: onReplyToPostId,
};
await path.add(dataToSet); // <= Correction 3
}
}
return null; // <= Correction 4
} catch (err) {
functions.logger.log(err);
}
} else {
return null;
}
});

Close MONGODB connection after data insertion

I want to populate my database with some random data. I have used Faker.js for generating that data. I'm using MongoDB on my localhost and all the data is properly following all the validation rules from the schema. I'm having problem with the closing connection of my connection after insertion of data. I want to close the connection soon after the data is populated. I'm using async function to be aware of all the things but something is not going right.
Here is my code seeds.js which is the script im using to populate database
const path = require("path");
require("dotenv").config({ path: path.resolve(__dirname, "../.env") });
var mongoose = require("mongoose");
mongoose.connect(process.env.MONGODB_URI);
require("../models/User");
require("../models/Item");
require("../models/Comment");
var Item = mongoose.model("Item");
var Comment = mongoose.model("Comment");
var User = mongoose.model("User");
const ItemData = require("../data/item.json");
const CommentData = require("../data/comment.json");
const UserData = require("../data/user.json");
async function InsertData() {
ItemData.forEach(async (item) => {
item.seller = item.seller.$oid;
const oldItem = await Item.find({ title: item.title });
if (!oldItem.length) {
var newItem = new Item(item);
await newItem.save();
} else {
console.log(item.slug);
}
});
UserData.forEach(async (user) => {
const oldUser = await User.find({ username: user.username });
if (!oldUser.length) {
var user = new User(user);
await user.save();
} else {
console.log(user.username);
}
});
CommentData.forEach(async (comment) => {
comment.item = comment.item.$oid;
comment.seller = comment.seller.$oid;
var newComment = new Comment(comment);
const oldComment = await Comment.find({ _id: newComment.id });
if (!oldComment.length) {
await newComment.save();
} else {
console.log(comment.body);
}
});
}
async function cleanup() {
await Item.deleteMany({}, () => console.log("Data Cleared Item"));
await Comment.deleteMany({}, () => console.log("Data Cleared Comment"));
await User.deleteMany({}, () => console.log("Data Cleared User"));
}
async function main() {
InsertData().then(async () => {
console.debug('Data Inserted. Closing connection.');
await mongoose.connection.close();
});
}
main();
Here is the stack trace of the error
/Users/karnikkanojia/Desktop/Anythink-Market-21cto/backend/node_modules/mongodb/lib/core/connection/pool.js:841
cb(new MongoError('pool destroyed'));
^
MongoError: pool destroyed
at Pool.write (/Users/karnikkanojia/Desktop/Anythink-Market-21cto/backend/node_modules/mongodb/lib/core/connection/pool.js:841:8)
at _command (/Users/karnikkanojia/Desktop/Anythink-Market-21cto/backend/node_modules/mongodb/lib/core/wireprotocol/command.js:120:10)
at command (/Users/karnikkanojia/Desktop/Anythink-Market-21cto/backend/node_modules/mongodb/lib/core/wireprotocol/command.js:28:5)
at Object.query (/Users/karnikkanojia/Desktop/Anythink-Market-21cto/backend/node_modules/mongodb/lib/core/wireprotocol/query.js:66:3)
at Server.query (/Users/karnikkanojia/Desktop/Anythink-Market-21cto/backend/node_modules/mongodb/lib/core/topologies/server.js:644:16)
at FindOperation.execute (/Users/karnikkanojia/Desktop/Anythink-Market-21cto/backend/node_modules/mongodb/lib/operations/find.js:38:12)
at /Users/karnikkanojia/Desktop/Anythink-Market-21cto/backend/node_modules/mongodb/lib/operations/execute_operation.js:144:17
at Server.selectServer (/Users/karnikkanojia/Desktop/Anythink-Market-21cto/backend/node_modules/mongodb/lib/core/topologies/server.js:832:3)
at Server.selectServer (/Users/karnikkanojia/Desktop/Anythink-Market-21cto/backend/node_modules/mongodb/lib/topologies/topology_base.js:342:32)
at executeWithServerSelection (/Users/karnikkanojia/Desktop/Anythink-Market-21cto/backend/node_modules/mongodb/lib/operations/execute_operation.js:131:12)
at /Users/karnikkanojia/Desktop/Anythink-Market-21cto/backend/node_modules/mongodb/lib/operations/execute_operation.js:70:9
at maybePromise (/Users/karnikkanojia/Desktop/Anythink-Market-21cto/backend/node_modules/mongodb/lib/utils.js:685:3)
at executeOperation (/Users/karnikkanojia/Desktop/Anythink-Market-21cto/backend/node_modules/mongodb/lib/operations/execute_operation.js:34:10)
at Cursor._initializeCursor (/Users/karnikkanojia/Desktop/Anythink-Market-21cto/backend/node_modules/mongodb/lib/core/cursor.js:534:7)
at Cursor._initializeCursor (/Users/karnikkanojia/Desktop/Anythink-Market-21cto/backend/node_modules/mongodb/lib/cursor.js:186:11)
at nextFunction (/Users/karnikkanojia/Desktop/Anythink-Market-21cto/backend/node_modules/mongodb/lib/core/cursor.js:737:10)
error Command failed with exit code 1.

Node function not working, await part is not getting executed in the given function

While hitting API I'm getting function from my services/ElasticSearch.js and for some reason function there is not working after the axios part.
In the below file I've called function elasticService.updateDocument this function has been brought from another file.
'''
class ProductController {
constructor() { }
async saveProduct(req, res) {
console.log('ITs coming here')
let { _id, Product } = req.body;
if (_id) delete req.body._id;
let elasticResult;
try {
if (Product && Product.Category) {
req.body.Category = Product.Category
delete Product.Category
}
if (Product && Product.URL) {
const exists = await ProductService.checkProductByUrl(Product.URL);
_id = exists._id
}
const result = await ProductService.saveProduct(req.body, _id);
if (result) {
if (_id) {
console.log('Here.... UPDATE')
const savedProduct = await ProductModel.createPayload(req.body);
console.log(savedProduct,'saved_product')
let elaticDoc = await this.createElasticDocData(savedProduct);
console.log(elaticDoc.id,'elasticResult')
elaticDoc.id = result._id;
elaticDoc = new Elastic(elaticDoc);
console.log(elaticDoc,'<----------elaticdoc-------------->')
elasticResult = await elasticService.updateDocument(JSON.stringify(elaticDoc), req.body.Category)
console.log(elasticResult,'elasticResult')
}
else {
console.log('Here.... ADD')
const savedProduct = await ProductModel.createPayload(result);
let elaticDoc = await this.createElasticDocData(savedProduct);
elaticDoc.id = result._id;
elaticDoc = new Elastic(elaticDoc);
elasticResult = await elasticService.createDocument(JSON.stringify(elaticDoc), req.body.Category)
}
const response = new Response(1, "Product is saved successfully", "", "", { product: result, elasticResult: elasticResult });
return res.status(200).send(response);
}
const response = new Response(0, "Error in saving Product", 0, "Product not saved", {});
return res.status(200).send(response);
} catch (error) {
const response = new Response(0, "Unexpected Error", 0, error, {});
return res.status(400).send(response);
}
}
'''
This is the elasticappsearch file where above mentioned is coming from and for some reason it's not working after axios.patch part.
'''
const private_key = process.env.elastic_private_key
const search_key = process.env.elastic_search_key
const axios = require("axios")
class ElasticAppSearch {
async updateDocument(body, engine) {
console.log('Its coming in updateDOCS here')
const response = await axios.patch(`${process.env.elastic_url}/${engine}/documents`, body, {
headers: {
Authorization: `Bearer ${private_key}`,
},
});
console.log(response,'<--===-=-=-=-=-=-=-=-=-=-=-=-response')
return response.data
}
'''

How to use dialogs with dispatch service?

I cannot use beginDialog with the LUIS dispatch. I want to use processHomeAutomation function to begin a new dialog but it gives me an error.
[onTurnError]: Error: DialogContext.beginDialog(): A dialog with an id
of 'TOP_LEVEL_DIALOG' wasn't found.
I imported TOP_LEVEL_DIALOG but still does not work. It only works with MainDialog which is the name of the current class.
const { ConfirmPrompt, DialogSet, DialogTurnStatus, OAuthPrompt, WaterfallDialog } = require('botbuilder-dialogs');
const { LogoutDialog } = require('./logoutDialog');
const { TopLevelDialog, TOP_LEVEL_DIALOG } = require('./topLevelDialog');
const { LuisRecognizer, QnAMaker } = require('botbuilder-ai');
const CONFIRM_PROMPT = 'ConfirmPrompt';
const MAIN_DIALOG = 'MainDialog';
const MAIN_WATERFALL_DIALOG = 'MainWaterfallDialog';
const OAUTH_PROMPT = 'OAuthPrompt';
let loggedIn = true;
class MainDialog extends LogoutDialog {
constructor() {
super(MAIN_DIALOG, process.env.connectionName);
this.addDialog(new TopLevelDialog());
this.addDialog(new OAuthPrompt(OAUTH_PROMPT, {
connectionName: process.env.connectionName,
text: 'Please Sign In',
title: 'Sign In',
timeout: 300000
}));
this.addDialog(new ConfirmPrompt(CONFIRM_PROMPT));
this.addDialog(new WaterfallDialog(MAIN_WATERFALL_DIALOG, [
this.promptStep.bind(this),
this.loginStep.bind(this),
this.displayTokenPhase1.bind(this),
this.displayTokenPhase2.bind(this)
]));
}
/**
* The run method handles the incoming activity (in the form of a DialogContext) and passes it through the dialog system.
* If no dialog is active, it will start the default dialog.
* #param {*} dialogContext
*/
async run(context, accessor) {
console.log(this.id)
if (loggedIn) {
const dialogSet = new DialogSet(accessor);
dialogSet.add(this);
const dialogContext = await dialogSet.createContext(context);
const results = await dialogContext.continueDialog();
const dispatchRecognizer = new LuisRecognizer({
applicationId: process.env.LuisAppId,
endpointKey: process.env.LuisAPIKey,
endpoint: `https://${process.env.LuisAPIHostName}.api.cognitive.microsoft.com`
}, {
includeAllIntents: true,
includeInstanceData: true
}, true);
const qnaMaker = new QnAMaker({
knowledgeBaseId: process.env.QnAKnowledgebaseId,
endpointKey: process.env.QnAAuthKey,
host: process.env.QnAEndpointHostName
});
this.dispatchRecognizer = dispatchRecognizer;
this.qnaMaker = qnaMaker;
const recognizerResult = await dispatchRecognizer.recognize(context);
// Top intent tell us which cognitive service to use.
const intent = LuisRecognizer.topIntent(recognizerResult);
// Next, we call the dispatcher with the top intent.
await this.dispatchToTopIntentAsync(context, intent, recognizerResult, dialogContext, results, dialogSet);
} else {
const dialogSet = new DialogSet(accessor);
dialogSet.add(this);
const dialogContext = await dialogSet.createContext(context);
const results = await dialogContext.continueDialog();
if (results.status === DialogTurnStatus.empty) {
console.log(this.id)
await dialogContext.beginDialog(this.id);
}
}
}
async promptStep(stepContext) {
return await stepContext.beginDialog(OAUTH_PROMPT);
}
async loginStep(stepContext) {
// Get the token from the previous step. Note that we could also have gotten the
// token directly from the prompt itself. There is an example of this in the next method.
const tokenResponse = stepContext.result;
if (tokenResponse) {
loggedIn = true;
await stepContext.context.sendActivity('You are now logged in.');
return await stepContext.prompt(CONFIRM_PROMPT, 'Would you like to view your token?');
}
await stepContext.context.sendActivity('Login was not successful please try again.');
return await stepContext.endDialog();
}
async displayTokenPhase1(stepContext) {
await stepContext.context.sendActivity('Thank you.');
const result = stepContext.result;
if (result) {
return await stepContext.beginDialog(OAUTH_PROMPT);
}
return await stepContext.endDialog();
}
async displayTokenPhase2(stepContext) {
const tokenResponse = stepContext.result;
if (tokenResponse) {
await stepContext.context.sendActivity(`Here is your token ${tokenResponse.token}`);
}
return await stepContext.endDialog();
}
/// QNA STUFF STATS HERE
async dispatchToTopIntentAsync(context, intent, recognizerResult, dialogContext, results) {
switch (intent) {
case 'automation':
await this.processHomeAutomation(context, recognizerResult.luisResult, dialogContext, results);
break;
case 'qna':
await this.processSampleQnA(context);
break;
default:
this.logger.log(`Dispatch unrecognized intent: ${intent}.`);
await context.sendActivity(`Dispatch unrecognized intent: ${intent}.`);
break;
}
}
async processHomeAutomation(context, luisResult, dialogContext, results, dialogSet) {
return await dialogContext.beginDialog(TOP_LEVEL_DIALOG);
}
async processSampleQnA(context) {
this.logger.log('processSampleQnA');
const results = await this.qnaMaker.getAnswers(context);
if (results.length > 0) {
await context.sendActivity(`${results[0].answer}`);
} else {
await context.sendActivity('Sorry, could not find an answer in the Q and A system.');
}
}
}
module.exports.MainDialog = MainDialog;

Categories

Resources