How to fetch particular documents in elasticsearch index - javascript

I want to fetch all the data of the corresponding particular field, and have a response of the elastic search.
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 35,
"relation": "eq"
},
"max_score": 0.44183275,
"hits": [
{
"_index": "allevents",
"_type": "_doc",
"_id": "jQPDaG0BcOh3oggcguoV",
"_score": 0.44183275,
"_source": {
"category": "sessions",
"contentid": "KqRLj2lWZ3",
"clientname": "omkarpathlab",
------------------
}]
I tried search function it returning an error.
var elasticsearch = require('elasticsearch');
var client = new elasticsearch.Client({
host: 'aaa',
log: 'trace',
apiVersion: '7.1'
});
client.search({
"size": 20,
"query": {
"query_string": {
"default_field": "clientname",
"query": "omkarlab"
}
}
}).then((res) => {
console.log("resultData", res);
}, (err) => {
console.log("err", err);
});
enter code here
Error showing:
{ Error: [illegal_argument_exception] request [/_search] contains unrecognized parameter: [query]
Please suggest me how to solve this kind of problem.

You should specify your field under default_field, not the value you are looking for. The field you are trying to query is clientname in your case, and the value you are looking for is omkarpathlab. So your query should be as follows:
"query": {
"query_string": {
"default_field": "clientname",
"query": "omkarpathlab"
}
}
edit. But your query inside of the body property:
client.search({
"size": 20,
"body": {
"query": {
"query_string": {
"default_field": "clientname",
"query": "omkarlab"
}
}
}
}).then((res) => {
console.log("resultData", res);
}, (err) => {
console.log("err", err);
});

You can use below code to connect to elasticsearch. I have tested it on 5.6 version
'use strict'
const { Client } = require('#elastic/elasticsearch')
const client = new Client({ node: 'http://XXX:9200' })
async function run () {
// Let's search!
const { body } = await client.search({
index: 'XXX',
type : 'XXX',
body: {
query: {
match_all: {}
}
}
})
console.log(body.hits.hits)
}
run().catch(console.log)
Code is a sample from https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/search_examples.html site.
for search documentation check below link
https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/api-reference.html#_search

Related

NodeJS - Iterating over API response to access inner fields from object?

I have the following NodeJs code in my AWS lambda as part of a larger lambda.
It calls an external API to return data regarding tournament schedules, I am able to get the response back from the API but I am unsure how to access the fields in the JSON response that I need.
This is my first time working with JS and NodeJS so I am unfamiliar with this.
const promise = new Promise((resolve, reject) => {
const options = {
host: 'MY_HOST',
path: 'MY_PATH',
headers: {
'key': 'value'
}
}
const req = https.get(options, res => {
let rawData = '';
res.on('data', chunk => {
rawData += chunk;
});
res.on('end', () => {
try {
resolve(JSON.parse(rawData));
} catch (err) {
reject(new Error(err));
}
});
});
req.on('error', err => {
reject(new Error(err));
});
});
// TODO - get promise result and iterate response
promise.then();
The response return is as follows (only showing first object for simplicity):
{
"_id": {
"$oid": "6346b02601a3c2111621c8e4"
},
"orgId": "1",
"year": "2023",
"schedule": [
{
"tournId": "464",
"name": "Fortinet Championship",
"timeZone": "America/Los_Angeles",
"date": {
"weekNumber": "37",
"start": {
"$date": {
"$numberLong": "1663200000000"
}
},
"end": {
"$date": {
"$numberLong": "1663459200000"
}
}
},
"format": "stroke",
"courses": [
{
"host": "Yes",
"location": {
"state": "CA",
"city": "Napa",
"country": "USA"
},
"courseName": "Silverado Resort and Spa (North Course)",
"courseId": "552"
}
],
"purse": {
"$numberInt": "8000000"
},
"winnersShare": {
"$numberInt": "1440000"
},
"fedexCupPoints": {
"$numberInt": "500"
}
}
]
}
The fields that I need access to are:
schedule[0].date.start
schedule[0].date.end
This is because I want to do e.g:
// loop each result and assert if current epoch is in the date Range
var currentTournamentId;
for(){
if(currentEpoch >= schedule.date.start && currentEpoch <= schedule.date.end) {
currentTournamentId = currentTournament.getId();
break;
}
}
How can I access these fields from the response?
Install body-parser andrequire it
let schedule = req.body.schedule;
schedule.forEach((item) => {
let start = item.date.start;
let end = item.date.end;
// do something
}

Update multiple or single object in an array with specified data from request

I am not great with MongoDB's advanced techniques.
My record in the MongoDB collection:
{
"_id": ObjectId("1"),
"manager": ObjectId("12345"),
"code": "PS",
"title": "Performance System",
"users": [
{
"_user": ObjectId("1"),
"role": "Member",
},
{
"_user": ObjectId("2"),
"role": "Member",
},
{
"_user": ObjectId("3"),
"role": "Member",
}
],
}
Node.js / ExpressJS
I created API to update the array like below but did not work.
const updateProjectMember = asyncHandler(async (req, res) => {
const { userID, role } = req.body.userData;
try {
const project = await Project.updateMany(
{ _id: req.params.projectID },
{ $set: { "users.$[selectedUser].role": role } },
{ arrayFilters: { "selectedUser._user": { $in: userID } } }
);
res.status(200).json(project);
} catch (error) {
res.status(400);
throw new Error(error);
}
I use the API parameter to get the project ID. Here is the request body data:
{
userID : ["2","3"];
role: "Admin"
}
So the API will get an array of userID to match and set all "role" fields to "Admin" to all matched.
I wanted the data to be like this:
{
"_id": ObjectId("1"),
"manager": ObjectId("12345"),
"code": "PS",
"title": "Performance System",
"users": [
{
"_user": ObjectId("1"),
"role": "Member",
},
{
"_user": ObjectId("2"),
"role": "Admin",
},
{
"_user": ObjectId("3"),
"role": "Admin",
}
],
}
Am I doing the right practice? If it is bad practice, what is the best way to solve this?
The query is fine. Just make sure that you pass the value with the exact type as in the MongoDB document.
var mongoose = require('mongoose');
const updateProjectMember = asyncHandler(async (req, res) => {
const { userID, role } = req.body.userData;
userID = userID.map(x => mongoose.Types.ObjectId(x));
try {
const project = await Project.updateMany(
{ _id: mongoose.Types.ObjectId(req.params.projectID) },
{ $set: { "users.$[selectedUser].role": role } },
{ arrayFilters: { "selectedUser._user": { $in: userID } } }
);
res.status(200).json(project);
} catch (error) {
res.status(400);
throw new Error(error);
}
}

Google People Api: Country not returned in Adresses field

I am trying to get the authenticated user's country by specifying "addresses" field in the People Api request as specified here.
This is the code:
router.post("/test_scope", (req, res) => {
const { idToken, accessToken } = req.body;
authenticationServices
.validateGoogleAccessToken(idToken, accessToken)
.then((response) => {
res.json(response);
});
});
const validateGoogleAccessToken = async (idToken, accessToken) => {
try {
const CLIENT_ID =
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.apps.googleusercontent.com";
const client = new OAuth2Client(CLIENT_ID);
const ticket = await client.verifyIdToken({
idToken,
audience: CLIENT_ID,
});
const payload = ticket.getPayload();
const { OAuth2 } = google.auth;
const oauth2Client = new OAuth2();
oauth2Client.setCredentials({ access_token: accessToken });
const peopleAPI = google.people({
version: "v1",
auth: oauth2Client,
});
const { data } = await peopleAPI.people.get({
resourceName: "people/me",
personFields: "birthdays,genders,addresses",
});
const { birthdays, genders, addresses, ageRanges } = data;
return data;
} catch (error) {
console.log("error: ", error);
throw new Error("Google token validation failed");
}
};
I have set up the addresses information in the account I am using to sign-in like this:
The is the whole response I get after sending the request:
{
"resourceName": "people/XXXXXXXXXXXXXXXXx",
"etag": "%XXXXXXXXXXXXXXXXXXXXXXXXXX",
"genders": [
{
"metadata": {
"primary": true,
"source": {
"type": "PROFILE",
"id": "XXXXXXXXXXXXXXXXXXXX"
}
},
"value": "female",
"formattedValue": "Female"
}
],
"birthdays": [
{
"metadata": {
"primary": true,
"source": {
"type": "PROFILE",
"id": "1XXXXXXXXXXXXXXXXXXXXXXXX"
}
},
"date": {
"month": 8,
"day": 9
}
},
{
"metadata": {
"source": {
"type": "ACCOUNT",
"id": "XXXXXXXXXXXXXXXXXXXXXXx"
}
},
"date": {
"year": 1996,
"month": 8,
"day": 9
}
}
],
"addresses": [
{
"metadata": {
"primary": true,
"source": {
"type": "PROFILE",
"id": "111110367350060808978"
}
},
"formattedValue": "XXXXXXXXXXXXX, XXXXX, XXXXX",
"type": "home",
"formattedType": "Home"
}
],
}
As you see the country field is missing in "addresses.
NOTE: I am retrieving the idToken and the accessToken from the FrontEnd, after the user clicks on the SignIn button:
import GoogleLogin from "react-google-login";
export class LoginPage extends Component {
onGoogleSignInSucceeded(response) {
const { accessToken, tokenId } = response;
}
render() {
const { errors } = this.state;
return (
<>
<GoogleLogin
clientId="XXXXXXXXXXXXXXXXXXXXXXXXX.apps.googleusercontent.com"
scope="https://www.googleapis.com/auth/user.birthday.read https://www.googleapis.com/auth/user.gender.read https://www.googleapis.com/auth/user.addresses.read"
// IMPORTANT
// https://developers.google.com/people/api/rest/v1/people/get#authorization-scopes
buttonText="Sign-in with your Google account"
onSuccess={this.onGoogleSignInSucceeded}
onFailure={this.onGoogleSignInFailed}
cookiePolicy={"single_host_origin"}
/>
</>
);
}
}
All fields on the address field are optional (see docs). This also includes the country. There is also no guarantee that the data is actually correct (the user can add invalid data to their google profile), so be careful about that and check for the verified metadata (see docs).
That being said you could try using a geocoding API to get the country from the formatted address. This could be made by using a reverse geocoding query (Google Geocoding API documentation).
Also notice that there are other fields that may contain an address. For example locations (see docs) can contain information about where they live.

Parameter in query graphql breaking JSON with NodeJS

my script connects to a graphql API by fetch and inserts the JSON return in the postgresql database, however when I insert the primaryLabels parameter into the query, it returns that my JSON is broken by a token>.
If I remove this parameter, everything goes perfectly, any solution?
I tried to turn the query into a string, but the code still fails
Code
let queryAPI = {"query": `{squads {name cards(includedOnKanban: true, closed: false, archived: false, cancelled: false, updatedSince: \"2020-01-01T00:00:00-0300\") { identifier title description status priority assignees { fullname email } secondaryLabel primaryLabels swimlane workstate}}}`};
(async () => {
try {
const rawResponse = await fetch('https://www.bluesight.io/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Bluesight-API-Token': 'token-here'
},
body: JSON.stringify(queryAPI)
});
const content = await rawResponse.json();
OUTPUT
at async C:\Users\Documents\Autoportal\Bluesight\index.js:35:25 {
name: 'FetchError',
message: 'invalid json response body at https://www.bluesight.io/graphql reason: Unexpected token < in JSON at position 0',
type: 'invalid-json'
JSON result example:
{
"data": {
"squads": [
{
"name": "SUPPORT IT",
"cards": [
{
"identifier": "06x38y",
"title": "ALL - Validate data",
"description": "review database.",
"status": null,
"priority": "medium",
"assignees": [
{
"fullname": "Carlos",
"email": "carlos#br.it.com",
}
],
"secondaryLabel": null,
"primaryLabels": [
"CLIENT"
]
}
]
}
]
} }
CONTENT
{
squads: [ { name: 'SUPPORT IT', cards: [Array] } ]
}

Better way to achieve desired results for the following code

So the scenario is that I have this following array as my input:
[
{
"failureMessage": "failed",
"data": {
"statusCode": 201,
"body": {
"id": "14975",
"key": "KEY-4855"
}
},
"testSetName": "search"
},
{
"failureMessage": null,
"data": {
"statusCode": 201,
"body": {
"id": "14975",
"key": "KEY-4856"
}
},
"testSetName": "download"
},
{
"failureMessage": "failed 2",
"data": {
"statusCode": 201,
"body": {
"id": "14975",
"key": "KEY-4857"
}
},
"testSetName": "search"
},
{
"failureMessage": null,
"data": {
"statusCode": 201,
"body": {
"id": "14975",
"key": "KEY-4858"
}
},
"testSetName": "download"
},
{
"failureMessage": "failed",
"data": {
"statusCode": 201,
"body": {
"id": "14975",
"key": "KEY-4859"
}
},
"testSetName": "backgrounds"
},
{
"failureMessage": null,
"data": {
"statusCode": 201,
"body": {
"id": "14975",
"key": "KEY-4860"
}
},
"testSetName": "backgrounds"
}
]
the above array contains objects which hold the data regarding test cases
And I want an array like this:
[
{
"testSetName": "search",
"testCases": ["KEY-4855", "KEY-4857"]
},
{
"testSetName": "download",
"testCases": ["KEY-4856", "KEY-4858"]
},...
]
The above array contains objects and those objects hold the name of the test set(testSetName) and all the test cases which are part of this test set as testCases.
Now, my code is below:
let results = testCasesObject.reduce(function (previousArr, currElement, currIndex) {
if (previousArr.length === 0) {
let obj = {testSetName: currElement.testSetName, testCases: []};
obj.testCases.push(currElement.data.body.key);
previousArr.push(obj);
}
else {
let isAdded = false;
for (let index = 0; index < previousArr.length; index += 1) {
if (previousArr[index].testSetName === currElement.testSetName) {
previousArr[index].testCases.push(currElement.data.body.key);
isAdded = true;
}
}
if (!isAdded) {
let obj = {testSetName: currElement.testSetName, testCases: []};
obj.testCases.push(currElement.data.body.key);
previousArr.push(obj);
}
}
return previousArr;
}, []);
console.log(results);
My code generates accurate results but I want to make it more efficient and I need help on this.
You could group by testSetName and reduce the array with a lookup for an already inserted item.
var array = [{ failureMessage: "failed", data: { statusCode: 201, body: { id: "14975", key: "KEY-4855" } }, testSetName: "search" }, { failureMessage: null, data: { statusCode: 201, body: { id: "14975", key: "KEY-4856" } }, testSetName: "download" }, { failureMessage: "failed 2", data: { statusCode: 201, body: { id: "14975", key: "KEY-4857" } }, testSetName: "search" }, { failureMessage: null, data: { statusCode: 201, body: { id: "14975", key: "KEY-4858" } }, testSetName: "download" }, { failureMessage: "failed", data: { statusCode: 201, body: { id: "14975", key: "KEY-4859" } }, testSetName: "backgrounds" }, { failureMessage: null, data: { statusCode: 201, body: { id: "14975", key: "KEY-4860" } }, testSetName: "backgrounds" }],
result = array.reduce((r, { testSetName, data: { body: { key } } }) => {
var item = r.find(o => o.testSetName === testSetName);
if (item) {
item.testCases.push(key);
} else {
r.push({ testSetName, testCases: [key] });
}
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
What you want to achieve contains an algorithm often called "group by". There is a lodash implementation you can use: _.groupBy
This will give you an object indexed by "testSetName". Then you can go forward and map this to your desired structure.
const indexedByTestSetName = _.groupBy(data, item => item.testSetName)
// {search: [{testSetName: 'search', failureMessage: 'failed', data: {}}, ...]
const tests = Object.keys(indexedByTestSetName).map(key => ({
testSetName: key,
testCases: indexedByTestSetName[key]
)})
// [{testSetName: 'search', testCases: [{testSetName: 'search', failureMessage: 'failed', data: {}}, ...]}]
This is more efficient in terms of "lines of code", but how the performance compares is hard to guess. If you don't face millions of entries, I would not bother.

Categories

Resources