Google Cloud DataStore GQL - gql

I am developing an adapter for waterline on NODEJS, I'm implementing the interface adapter but I have a problem to describe schema for google cloud datastore, I need to get the list of properties of a kind but I don't know how to get the properties. I have tried this SQL but only I get the kinds without the properties.
select __key__ from __kind__
How is the equivalent of Mysql describe on GQL?
thanks

For anyone who wants to get all the properties of a kind, the query is so easy. the next code is the example of the kind, the name of the kind is Task.
example of the creation of the kind
const kind = 'Task';
const name = '100';
const taskKey = datastore.key([kind, name]);
const task = {
key: taskKey,
data: {
description: 'not more tasks',
}
};
datastore
.save(task)
.then(() => {
console.log('the creation ends fine');
})
.catch(err => {
console.error('ERROR:', err);
});
example of the query that returns the properties of the kinds
select * from __Stat_PropertyName_Kind__ where kind_name = 'Task'
example of NODEJS code that returns and prints the properties of a kind
const query = datastore
.createQuery('__Stat_PropertyName_Kind__')
.filter('kind_name', '=', 'Task');
datastore.runQuery(query).then(results => {
var response = results[0];
var schema = response[0];
console.log(schema.kind_name);
console.log(schema.property_name);
});
the result of the query are the next:
Task
description

Related

firebase cloud functions iterate over collection

I am building a forum, and when a person comments on a thread, I would like to email everyone that someone has added a comment. This requires iterating over a firestore collection. How do I do this using firebase cloud functions?
exports.onCommentCreation = functions.firestore.document('/forum/threads/threads/{threadId}/comments/{commentId}')
.onCreate(async(snapshot, context) => {
var commentDataSnap = snapshot;
var threadId = context.params.threadId;
var commentId = context.params.commentId;
// call to admin.firestore().collection does not exist
var comments = await admin.firestore().collection('/forum/threads/threads/{threadId}/comments/');
// iterate over collection
});
You need to run get query, not sure what is admin here, but you can do like this:
const citiesRef = db.collection('cities'); // pass your collection name
const snapshot = await citiesRef.where('capital', '==', true).get(); // query collection
if (snapshot.empty) {
console.log('No matching documents.');
return;
}
snapshot.forEach(doc => {
console.log(doc.id, '=>', doc.data());
});
You can check this link, for more details.
Also, I would suggest you go through this link to correctly set up the cloud function for firestore if there are any issues with it.

How to get userId from Firestore on Node.js backend?

Im new to firebase and I am having trouble setting up the user profile route on my app. Im trying to make it so that the userId stored in Firestore can be retrieved and all the posts made by that specific user will be displayed on the user profile page. Please any help would be appreciated!
This is my Firestore database :
and this is what I have so far but it is not displaying all the posts associated with the user id
const express = require("express");
const router = express.Router();
const firestore = require("firebase/firestore");
const db = firestore.getFirestore();
router.get("/", (req, res) => {
res.send("No user id provided");
});
router.get("/:uid", (req, res) => {
const uid = req.params.uid;
const userPost = firestore.getDoc(firestore.doc(db, "reviews", uid));
userPost(uid, req.query && req.query.dev === "true")
.then((user) => {
return res.send(user);
})
.catch((e) => {
return res.send(e);
});
});
module.exports = router;
This line gets the single (probably non-existant) post at /reviews/:uid:
const userPost = firestore.getDoc(firestore.doc(db, "reviews", uid));
What you are looking to do is build a query for documents in the collection /reviews where docData.userId = uid.
const reviewsColRef = firestore.collection(db, "reviews");
const userPostsQuery = firestore.query(reviewsColRef, firestore.where("userId", "==", uid));
const userPostsPromise = firestore.getDocs(userPostsQuery);
userPostsPromise
.then((querySnapshot) => {
const postsArray = querySnapshot.docs.map(docSnap => {
const docData = { id: docSnap.id, ...docSnap.data() };
delete docData.userId; // it's the same for every post, may as well omit it
delete docData.email; // same as above
return docData;
});
res.json({ posts: postsArray, count: postsArray.length });
})
.catch((err) => {
// don't send the full error object to the client,
// instead you should log the error and send the
// client as little information as possible
console.error(`Failed to get user posts for firebase:${uid}`, err);
res.status(500).json({ error: err.code || err.message }); // Don't forget to use an appropriate status code!
});
Notes:
I recommend using destructuring to import the Firestore lib. Importing it as firestore negates the benefits of the modular SDK of only importing what you need.
import { getFirstore, query, collection, ... } from "firebase/firestore";
If this code is running on a server you control, consider switching to the Firebase Admin SDK instead as this allows you to bypass security rules and has relaxed rate limits.
import { getFirestore, query, collection, ... } from "firebase-admin/firestore";
As a side note, if an import from the SDK conflicts with a name you want to use elsewhere, you can rename it. You might see this when using the RTDB and storage together as they both export ref:
import { getDatabase, ref: rtdbRef } from "firebase/database";
import { getStorage, ref: storageRef } from "firebase/storage";
const userDataRef = rtdbRef(getDatabase(), "users", uid, "data");
const imgStorageRef = storageRef(getStorage(), "path/to/image.png");
Treat emails as sensitive data akin to a phone number. Nobody likes spam and limiting ways to rip emails from your database is good practice. Unless you are working on an internal tool for a corporate network, you should hide the user's email as much as possible.
Email addresses should not be stored with reviews. Instead keep a collection with documents for each user (e.g. document at /userProfile/:uid) and limit access to privileged users.
Consider adding a 404 Not Found error when a user doesn't exist.
Consider adding authentication to restrict access to your API.

Convert Oracle query output to json (Oracle / NodeJS)

I'm doing an app with React / Express (NodeJS) / Oracle,
I have an Express route that gets datas from an Oracle table,
Here's a part of the code in the route :
let conn;
try {
conn = await oracledb.getConnection(config);
const result = await conn.execute("select JSON_OBJECT ('departement' VALUE departement, 'ufh' VALUE ufh, 'libelle' VALUE libelle, 'nomhopital' VALUE nomhopital, 'typeservice' VALUE typeservice, 'actif' VALUE actif) from Z_SOUPAP2CARTESITE where actif=1");
res.send(result.rows);
}
But when I go on the route in the browser, the datas have this shape :
[["92","028X362","ABC ACCUEIL URG MEDECINE","ANTOINE BECLERE","ADULTE",1],["92","028X472","ABC URGENCES PEDIATRIQUE","ANTOINE BECLERE","PEDIATRIE",1],["92","014X545","APR ACCEUIL URGENCES ADU","AMBROISE PARE","ADULTE",1]]
and I want this :
[
{"departement":"92","ufh":"028X362","libelle":"ABC ACCUEIL URG MEDECINE","nomhopital":"ANTOINE BECLERE","typeservice":"ADULTE","actif":1},
{"departement":"92","ufh":"028X472","libelle":"ABC URGENCES PEDIATRIQUE","nomhopital":"ANTOINE BECLERE","typeservice":"PEDIATRIE","actif":1}
]
Why are you using JSON_VALUE? The driver returns native JavaScript objects. You could write the query as:
select department "department",
ufh "ufh",
libelle "libelle",
nomhopital "nomhopital",
typeservice "typeservice"
from Z_SOUPAP2CARTESITE
where actif=1
In the query above, the double-quoted column aliases are used to control the case of the keys.
By default, the driver returns an array of arrays (no keys). If you want an array of objects, you need to pass an options object to execute that changes the outFormat. See this part of the doc: https://oracle.github.io/node-oracledb/doc/api.html#queryoutputformats
Here's an example from the doc:
const result = await connection.execute(
`SELECT department_id, department_name
FROM departments
WHERE manager_id < :id`,
[110], // bind value for :id
{ outFormat: oracledb.OUT_FORMAT_OBJECT }
);
console.log(result.rows);
If you want to use the JSON generation functions in Oracle, such as JSON_VALUE, you have to avoid a double parse - just access the string as JSON.
See this series for more info on building a REST API with Node.js and Oracle Database: https://jsao.io/2018/03/creating-a-rest-api-with-node-js-and-oracle-database/
The below solution works for me:
app.post('/getData', async function (req, res) {
try {
const result = await connection.execute("SELECT * FORM USER", [], { outFormat: oracledb.OUT_FORMAT_OBJECT });
// print response in json file: import => const fs = require("fs");
fs.writeFile("response.json", JSON.stringify(result.rows), err => {
if (err) throw err;
console.log('File successfully written to disk');
});
res.send({
data: result.rows,
});
} catch (err) {
console.log(err);
}});

Not getting firestore document field data even though document has couple of fields

I have migrated the firebase real time data to cloud firestore through the below nodejs script:
var fireastoreDB = admin.firestore();
var db = admin.database();
var ref = db.ref("/users");
let items = [];
ref.once("value", function(snapshot) {
let collectionRef = fireastoreDB.collection("users");
snapshot.forEach(item => {
collectionRef.doc(item.key).set(item.val());
});
I got the data into cloud firestore. Now I have to implement REST APIs for this data in the nodejs.
var docusRef = db.collection("users").get().then( (data) => {
console.log(data);
data.forEach( item => {
let docObj = item.data();
console.log(docObj['Coins']);
console.log(docObj['Coins']['Total Coins']);
});
});
from this code, I am able to get all documents field data. But when I am trying to get specific document data directly I was getting undefined(exists: false) but data was there under this document.
var db = admin.firestore();
var docusRef = db.collection("users").doc('Atest - 12345')
docusRef.get().then(function (col) {
var name=col.get("Coins");
console.log(name); // undefined & exists: false
});
when i have added document/fields manually from firebase console, I was getting data.
Is this issue with migrated data or what?
Can anyone please find the issue.
The get() method returns "a Promise resolved with a DocumentSnapshot containing the current document contents". Therefore you have to use the data() method of the DocumentSnapshot to get the fields of the document, as follows:
docusRef.get().then(function (col) {
var name=col.data().Coins;
console.log(name);
});

Google Cloud Datastore: lookup and update in one transaction

I'm following the Cloud Datastore sample from the Google documentation as well as the Github sample, following the tasks sample. I'm trying to make a single function call, and mark a task as done by looking it up by the description.
function markDoneByDesc(queryString) {
const query = datastore
.createQuery('Task')
.filter('description', '=', queryString);
var taskKeyId;
datastore
.runQuery(query)
.then(results => {
const tasks = results[0];
console.log('Task found:', tasks[0]);
// I realize there might be multiple tasks with the same desc,
// but I want to update just one for now
taskKeyId = tasks[0][datastore.KEY].id;
console.log('Saving the task Key ID', taskKeyId);
return taskKeyId;
})
.then((taskKeyId) => {
console.log('Calling markDone with task Key ID', taskKeyId);
markDone(taskKeyId); // From the original function in the sample
console.log('Updated task');
})
.catch(err => {
console.error('ERROR:', err);
});
}
Right now, the update doesn't happen :(
I found the solution, thanks to #callmehiphop's help!
Looks like I need to convert the taskKeyId that is returned in the datastore query into an integer, and then pass it to the markDone() function. Otherwise it is passed as a string and the lookup by that ID Key fails.
Here's what the correct code should look like (note the parseInt() in the first return statement):
function markDoneByDesc(queryString) {
const query = datastore
.createQuery('Task')
.filter('description', '=', queryString);
var taskKeyId;
datastore
.runQuery(query)
.then(results => {
const tasks = results[0];
console.log('Task found:', tasks[0]);
// I realize there might be multiple tasks with the same desc,
// but I want to update just one for now
taskKeyId = tasks[0][datastore.KEY].id;
console.log('Saving the task Key ID', taskKeyId);
return parseInt(taskKeyId,10);
})
.then((taskKeyId) => {
console.log('Calling markDone with task Key ID', taskKeyId);
markDone(taskKeyId); // From the original function in the sample
console.log('Updated task');
})
.catch(err => {
console.error('ERROR:', err);
});
}

Resources