Elastic search and Firebase: Result limit change and weird query results - javascript

I have setup an elastic search instant, created a Firebase project and run flashlight on my localhost. When I query the Firebase database in the default path (search/request) I get 10 results created in the search/response path in my database instance on Firebase.
Can someone more experienced on this please explain:
How can I change the result limit to more than 10 results on Firebase?
(I tried tinkering with SearchQueue.jsusing the code in the bottom but i didn't manage to make it work.
Why the search results when the queries are performed without specifying index and type return the total number of entries on elastic server and therefore irrelevant results on Firebase?
I used postman for the ReST calls (PUT) on firebase and the JSON content was sent over to /search/request/
This json content worked in terms of results:
{ "index": "chatmessages", "type": "chat", "query": "georgebest"}
but this one did not:
{"query": "georgebest"}
Both returned a Status: 200 OK .
Let me add that using Sense and running the same query the results are totally correct. The issue occurs when flashlight is used.
Please note that I don't use any rules and I left the Firebase database open for testing purposes.
Let me know if any additional information is required..Thanks.
code snippet for 1):
SearchQueue.prototype = {
_process: function(snap) {
var dat = snap.val();
var key = snap.key;
if (this._assertValidSearch(key, dat)) {
// Perform (a very simple) ElasticSearch query
var searchProps = {
index: dat.index,
type: dat.type,
//added variables
size : dat.size,
from : dat.from
};

It looks like you were running into a bug fixed in the 0.2.0 release.
Note that in the latest release query was replaced by q or body to be inline with ES. (query still works for now)
A more useful sample is now included in the doc here.
{
"from" : 0,
"size" : 50,
"body": {
"query": {
"match": {
"_all": "foo"
}
}
}
}
Using q for the sql lite format also works:
{
"from" : 0,
"size" : 50,
"q": "foo"
}

I found out what was causing the issues in my case (probably also caused via some other means as Kato suggested above).
For the first issue:
I was running a previous version of node.js in my system and what I did was to update the node.js to version 6.9.1 and then upgrade npm to version 4.0.2 (using npm install npm#latest -g ) afterwards I reinstated all the required node_modules (npm install --save firebase and npm install --save elasticsearch) and voila! it worked!
The code I used for the size and from variables:
SearchQueue.prototype = {
_process: function(snap) {
var dat = snap.val();
var key = snap.key;
if (this._assertValidSearch(key, dat)) {
// Perform (a very simple) ElasticSearch query
var searchProps = {
index: dat.index,
type: dat.type,
//added variables
size : dat.size,
from : dat.from,
};
The content of the json file :
{ "index":"chatmessages","type" : "chat", "query":"some_query", "from":"0", "size":"20"}
For the second issue:
The results were not passing correctly to elastic server, returning "undefined" and a hit number of all results stored.
I used postman to send the JSON in the following URL firebase_address/search/request/some_object.json
but just for reference if you want to do it manually in firebase, you should create something like this:
Of course the way to go from here is with the latest version as suggested above!

Related

Azure Functions - Value cannot be null. (Parameter 'connectionString')

I was trying to setup simple Azure Function to read a XML stream and sync it back to the database. My plan was to use a Time Trigger to execute the function once per day.
Howerver, things are not looking great. I'm getting the following error, even if I don't use a database:
[Error] Executed 'Functions.<func-name>' (Failed, Id=<func-id>, Duration=1ms)Value cannot be null. (Parameter 'connectionString')
I'm currently trying to execute the following function:
module.exports = async function(context, req) {
context.res = {
body: "Success!"
};
};
Same result. I can't run it.
I've added a Connection String to the Configuration -> Connection Strings (I thought that I've missed that, based on the message).
My functions.json file looks like:
{
"bindings": [
{
"name": "myTimer",
"type": "timerTrigger",
"direction": "in",
"schedule": "0 0 * * * *"
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
I've also tried running a C# function - same result.
So, what have I missed?
Logging from Microsoft to it's finest.
AzureWebJobsStorage App Setting was missing.
Solution:
Create Storage account (or use existing one)
Go to your Function App's Configuration
Add AzureWebJobsStorage with a connection string to your Storage account (can be found at Storage Account Overview -> Access Keys)
In my case the error was Microsoft.Extensions.Configuration.AzureAppConfiguration value cannot be null: parameter (connectionString)
This happened because I has installed Microsoft.Extensions.Configuration.AzureAppConfiguration in my Function to DI the configuration into my main function. The Startup.cs line string cs = Environment.GetEnvironmentVariable("MyDifferentConnectionString"); was not able to find an environment variable for MyDifferentConnectionString, so this needed to be added to the Function config.
Go to App Configuration (or create one)
Access Keys (under Settings)
Copy Connection String
Go to your Function
Configuration (under Settings)
Add a new Application Settings with the name of your environment variable and paste the value
Save and restart your Function

How to save a document with a dynamic id into Cloud Firestore? Always changing

I am using Cloud Firestore as my database
This is my form codes on my webpage that creates a new document into my Cloud Firestore collection called "esequiz". So how do I code it in such a way that it always plus 1 to the number of documents there are in the database? And also set a limit to having the amount of documents inside the database
form.addEventListener('submit', (e) => {
e.preventDefault();
db.collection('esequiz').add({
question: form.question.value,
right: form.right.value,
wrong: form.wrong.value
});
form.question.value = '';
form.right.value = '';
form.wrong.value = '';
});
It currently works but it will show up as an auto generated ID. How do I make it carry on from the numbers, like as my current documents? When i save I would like it to read the current last document id, OR simply count the number of documents, then just + 1
Insight from Andrei Cusnir, counting documents in Cloud Firestore is not supported.
Now I am trying Andrei's approach 2, to query documents in descending order, then using .limit to retrieve the first one only.
UPDATED
form.addEventListener('submit', (e) => {
e.preventDefault();
let query = db.collection('esequiz');
let getvalue = query.orderBy('id', 'desc').limit(1).get();
let newvalue = getvalue + 1;
db.collection('esequiz').doc(newvalue).set({
question: form.question.value,
right: form.right.value,
wrong: form.wrong.value
});
form.question.value = '';
form.right.value = '';
form.wrong.value = '';
});
No more error, but instead, the code below returns [object Promise]
let getvalue = query.orderBy('id', 'desc').limit(1).get();
So when my form saves, it saves as [object Promise]1, which I don't know why it is like this. Can someone advise me on how to return the document id value instead of [object Promise]
I think it is because I did specify to pull the document id as the value, how do I do so?
UPDATED: FINAL SOLUTION
Played around with the codes from Andrei, and here are the final codes that works. Much thanks to Andrei!
let query = db.collection('esequiz');
//let getvalue = query.orderBy('id', 'desc').limit(1).get();
//let newvalue = getvalue + 1;
query.orderBy('id', 'desc').limit(1).get().then(querySnapshot => {
querySnapshot.forEach(documentSnapshot => {
var newID = documentSnapshot.id;
console.log(`Found document at ${documentSnapshot.ref.path}`);
console.log(`Document's ID: ${documentSnapshot.id}`);
var newvalue = parseInt(newID, 10) + 1;
var ToString = ""+ newvalue;
db.collection('esequiz').doc(ToString).set({
id: newvalue,
question: form.question.value,
right: form.right.value,
wrong: form.wrong.value
});
});
});
If I understood correctly you are adding data to the Cloud Firestore and each new document will have as name an incremental number.
If you query all the documents and then count how many are of them, then you are going to end up with many document reads as the database increases. Don't forget that Cloud Firestore is charging per document Read and Write, therefore if you have 100 documents and you want to add new document with ID: 101, then with the approach of first reading all of them and then counting them will cost you 100 Reads and then 1 Write. The next time it will cost you 101 Reads and 1 Write. And it will go on as your database increases.
The way I see is from two different approaches:
Approach 1:
You can have a single document that will hold all the information of the database and what the next name should be.
e.g.
The structure of the database:
esequiz:
0:
last_document: 2
1:
question: "What is 3+3?
right: "6"
wrong: "0"
2:
question: "What is 2+3?
right: "5"
wrong: "0"
So the process will go as follows:
Read document "/esequiz/0" Counts as 1 READ
Create new document with ID: last_document + 1 Counts as 1 WRITE
Update the document that holds the information: last_document = 3; Counts as 1 WRITE
This approach cost you 1 READ and 2 WRITES to the database.
Approach 2:
You can load only the last document from the database and get it's ID.
e.g.
The structure of the database (Same as before, but without the additional doc):
esequiz:
1:
question: "What is 3+3?
right: "6"
wrong: "0"
2:
question: "What is 2+3?
right: "5"
wrong: "0"
So the process will go as follows:
Read the last document using the approach described in Order and limit data with Cloud Firestore documentation. So you can use direction=firestore.Query.DESCENDING with combination of limit(1) which will give you the last document. Counts as 1 READ
Now you know the ID of the loaded document so you can create new document with ID: that will use the loaded value and increase it by 1. Counts as 1 WRITE
This approach cost you 1 READ and 1 WRITE in total to the database.
I hope that this information was helpful and it resolves your issue. Currently counting documents in Cloud Firestore is not supported.
UPDATE
In order for the sorting to work, you will also have to include the id as a filed of the document that so you can be able to order based on it. I have tested the following example and it is working for me:
Structure of database:
esequiz:
1:
id: 1
question: "What is 3+3?
right: "6"
wrong: "0"
2:
id:2
question: "What is 2+3?
right: "5"
wrong: "0"
As you can see the ID is set the same as the document's ID.
Now you can query all the documents and order based on that filed. At the same time you can only retrieve the last document from the query:
const {Firestore} = require('#google-cloud/firestore');
const firestore = new Firestore();
async function getLastDocument(){
let query = firestore.collection('esequiz');
query.orderBy('id', 'desc').limit(1).get().then(querySnapshot => {
querySnapshot.forEach(documentSnapshot => {
console.log(`Found document at ${documentSnapshot.ref.path}`);
console.log(`Document's ID: ${documentSnapshot.id}`);
});
});
}
OUTPUT:
Found document at esequiz/2
Document's ID: 2
Then you can take the ID and increase it by 1 to generate the name for your new document!
UPDATE 2
So, the initial question is about "How to store data in the Cloud Firestore with documents having incremental ID", at the moment you are facing issues of setting up Firestore with you project. Unfortunately, the new raised questions should be discussed in another Stackoverflow post as they have nothing to do with the logic of having incremental IDs for the document and it is better to keep one issue per question, to give better community support for members that are looking for a solution about particular issues. Therefore, I will try to help you, in this post, to execute a simple Node.js script and resolve the initial issue, which is storing to Cloud Firestore documents with incremental IDs. Everything else, on how to setup this in your project and how to have this function in your page, should be addressed in additional question, where you also will need to provide as much information as possible about the Framework you are using, the project setup etc.
So, lets make a simple app.js work with the logic described above:
Since you have Cloud Firestore already working, this means that you already have Google Cloud Platform project (where the Firestore relies) and the proper APIs already enabled. Otherwise it wouldn't be working.
Your guide in this tutorial is the Cloud Firestore: Node.js Client documentation. It will help you to understand all the methods you can use with the Firestore Node.js API. You can find helpful links for adding, reading, querying documents and many more operations. (I will post entire working code later in this steps. I just shared the link so you know where to look for additional features)
Go to Google Cloud Console Dashboard page. You should login with your Google account where your project with the Firestore database is setup.
On top right corner you should see 4 buttons and your profile picture. The first button is the Activate Cloud Shell. This will open a terminal on the bottom of the page with linux OS and Google Cloud SDK already install. There you can interact with your resources within GCP projects and test your code locally before using it in your projects.
After clicking that button, you will notice that the terminal will open in the bottom of your page.
To make sure that you are properly authenticated we will set up the project and authenticate the account again, even if it is already done by default. So first execute $ gcloud auth login
On the prompted question type Y and hit enter
Click on the generated link and authenticate your account on the prompted window
Copy the generated string back to the terminal and hit enter. Now you should be properly authenticated.
Then setup the project that contains Cloud Firestore database with the following command: $ gcloud config set project PROJECT_ID. Now you are ready to build a simple app.js script and execute it.
Create a new app.js file: nano app.js
Inside paste my code example that can be found in this GitHub link. It contains fully working example and many comments explaining each part therefore it is better that it is shared through GitHub link and not pasted here. Without doing any modifications, this code will execute exactly what you are trying to do. I have tested it my self and it is working.
Execute the script as: node app.js
This will give you the following error:
Error: Cannot find module '#google-cloud/firestore'
Since we are importing the library #google-cloud/firestore but haven't installed it yet.
Install #google-cloud/firestore library as follows: $ npm i #google-cloud/firestore. Described in DOC.
Execute the script again: $ node app.js.
You should see e.g. Document with ID: 3 is written.
If you execute again, you should see e.g. Document with ID: 4 is written.
All those changes should appear in your Cloud Firestore database as well. As you can see it is loading the ID of the last document, it is creating a new ID and then it creates a new document with the given arguments, while using the new generated ID as document name. This is exactly what the initial issue was about.
So I have shared with you the full code that works and does exactly what you are trying to do. Unfortunately, the other newly raised issues, should be addressed in another Stackoverflow post, as they have nothing to do with the initial issue, which is "How to create documents with incremental ID". I recommend you to follow the steps and have a working example and then try to implement the logic to your project. However, if you are still facing any issues with how to setup Firestore in your project then you can ask another question. After that you can combine both solutions and you will have working app!
Good luck!
I don't think the way you are trying to get the length of the collection is right and I am entirely not sure what is the best way to get that either. Because the method you are trying to implement will cost you a lot more as you are trying to read all the records of the collection.
But there can be alternatives to get the number you require.
Start storing the ID in the record and make the query with limit 1 and a descending sort on ID.
Store the latest number in another collection and increment that every time you create a new record, And fetch the same whenever needed.
These methods might fail if concurrent requests are being made without transactions.

Retrieve PRs that reference an issue via Github API v4

I have a graphql query which enables me to retrieve all issues for a repository, filtered by some criteria.
Now in my team, we have one repository for the code, and one for the issues, so external people can file issues without having access to our internal discussions.
When we make a PR, we reference the original issue on the issues repo.
What I want to do, is get all the PRs in the second repo that reference issues in the first one.
So far I have
const query = `{
repository(owner:"${owner}", name:"${repository}") {
issues(last:20, states:CLOSED, labels: ["type:bug"]) {
edges {
node {
title
url
labels(first:20) {
edges {
node {
name
}
}
}
}
}
}
}
}`;
This gets me the issues on the first repo, but can I get the PRs on the second in the same GraphQL call, or should I collect the issue IDs on the TS side and make a different query?

can not get data with MysqlSubscription of numtel:mysql for meteor

I am using meteor to do full stack javascript work.And I want to use mysql instead of mongodb.I find numtel:mysql on github, which is a Reactive MySQL for Meteor.
On the server side
Meteor.publish('test', function(){
let array = liveDb.select(
'select * from tasks',
[ { table: 'tasks' } ]
);
console.log('publish test mysql')
console.log(array);
return array;
});
on the client side
let mysqlData = new MysqlSubscription('test');
console.log('subscribe mysql data at client');
console.log(mysqlData);
console.log(mysqlData.length);
console.log(mysqlData.subscriptionId);
console.log(mysqlData[0]);
console.log(mysqlData[1]);
However, I can not get data on the client.And there is a strange phenomenon.From the logs, I find data of mysqlData.However, mysqlData.length is 0, mysqlData[0] and mysqlData[1] are undefined.
Who can help me?
You might want to call mysqlData.reactive() and check if it is ready by using mysqlData.ready() first.
In case the subscription does not work (it does not update the data automatically), you should make sure that you config your MySQL server correctly following the installation instruction.
For me, I could not make it work when I used capital letter on the database name, you should check it also.

when I try to use find inside loopback model js file.iam getting error as Error: Cannot call user.find(). The find method has not been setup

Error: Cannot call user.find(). The find method has not been setup. The PersistedModel has not been correctly attached to a DataSource!
user.js is inside server/models/user.js
module.exports = function(User) {
User.find({where: {id:'3'}}, function(err,data) {
console.log(err);
console.log(data);
});
};
Your current model-config.json file has this line:
"user": { "dataSource": "db" }
Make the U capital in user as this is creating a new model user with lowercase letter and i think you haven't created its model files like user.js and user.json. It looks like you want to extend the built-in User model, in that case you can use this lowercase user model but keep both the model definitions in the model-config.js and use User as base in user.json file. Check Docs there is clear explanation for this
This is nothing to do with the "user" having a lowercase "u". Following the StrongLoop documentation, it looks like you've generated a model but not linked it to a data source.
In the documentation, it advises you to create a model and then change the datasource afterward. When you generate your model, the storage that is available for you to set will only be "db", which is an in-memory provider.
To get your API path to work correctly, firstly generate your model using:
slc loopback:model
Once you have generated your model, then run:
slc loopback:datasource
Which will then prompt you to fill in some options about your data source. Here's an example using MongoDB (note, where there is no data after the ':' is where you press enter to use the default value):
? Enter the data-source name: name_i_want_to_use_for_this
? Select the connector for name_i_want_to_use_for_this: MongoDB (supported by StrongLoop)
Connector-specific configuration:
? Connection String url to override other settings (eg: mongodb://username:password#hostname:port/database):
? host: localhost
? port:
? user:
? password:
? database: mydbname
? Install loopback-connector-mongodb#^1.4 Yes
This will then provide you with a connection provider called name_i_want_to_use_for_this. Now go into your /server/model-config.json and then scroll down to the name of your model and you will see:
"name_of_my_model": {
"dataSource": "db",
"public": true
}
Change this to:
"name_of_my_model": {
"dataSource": "name_i_want_to_use_for_this",
"public": true
}
Now you're done, go back into your strongloop project directory and run node ., and browse to http://localhost:3000/explorer. Go to the method you wanted to test, and test it in the explorer again, and it should now insert the data into the model.
To test this has worked, create a new record using the explorer, and then query its ID using the explorer.

Categories