How to update Elasticsearch dynamic data multiple fields using UpdateByQuery in NodeJS - node.js

How to update Elasticsearch data multiple fields using UpdateByQuery in NodeJS ?
Note - My data is coming dynamically. I can't pass static value. I have to pass like - data.name, data.id
Code -
function updateInELK(data) { // Update by Id
const updateScript = {
inline: {
"ctx._source.name = "+data.name,
"ctx._source.role = "+data.role,
};
return new Promise((resolve, reject) => {
elasticsearch.updateByQuery({
index: indexName,
body: {
query: { match: { id: data.id } },
script: updateScript,
lang: 'painless',
}
}).then((response) => {
resolve(response);
}).catch((err) => {
console.log(err);
reject("Elasticsearch ERROR - data not updated")
})
});
}
Error -
TypeError: "ctx._source.name = " is not a function
Please let me know, if any other options are there. I can't update using id, because I don't know the id. I wanted to use updateByQuery, with conditions in the query parameters.

Here are the solutions -
await esClient.updateByQuery({
index: "data",
type: "doc",
refresh: true,
body:{
query:{
match: {
dataId: "70897e86-9d69-4700-b70e-881a7f74e9f9"
}
},
script:{
lang:"painless",
source:`ctx._source.data='This is updated test data';ctx._source.updatedAt=params.date;ctx._source.segmentId=params.segmentId`,
params:{
date: Date.now(),
segmentId: null
}
}
}
});

Related

How to remove a nested attribute from dynamodb table?

How to remove a nest attribute from dynamodb table on the basis of id? I m using nodejs(Typescript) with local dynamodb.
// check if post exists
const post = await dynamo.get({
TableName: "PostTable",
Key: { id: event.body.postId }
}).promise();
if (!post.Item) {
return formatJSONResponse({
message: `no post with this id`,
statuscode: 404
});
}
const params = {
TableName: "PostTable",
Key: { id: event.body.postId },
UpdateExpression:
"REMOVE comments.#id",
ExpressionAttributeValues: {
"#id": event.body.id
},
ReturnValues : "UPDATED_NEW"
}
let res= await dynamo.update(params).promise();
return formatJSONResponse({
message: `Comment has been removed
event,
result: res
});
dynamobdb table picture

Typeorm find options with order and where

I would like to order this find function through the table relation.
const [people, total] = await typePersonServiceInstance.find(
{
take,
skip,
where: (qb: any) => {
qb.where('person.type IN (:...type)', { type });
qb.andWhere('person.status IN (:...status)', { status });
if (query.search) {
qb.andWhere(new Brackets((subQb) => {
subQb.where('name like :name', { name: `%${query.search}%` });
subQb.orWhere('fantasyName like :fantasyName', { fantasyName: `%${query.search}%` });
subQb.orWhere('person.city like :city', { city: `%${query.search}%` });
subQb.orWhere('person.state like :state', { state: `%${query.search}%` });
subQb.orWhere('person.id = :id', { id: query.search });
}));
}
},
order: {
person: {
status: 'ASC'
}
}
},
);
The issue i'm facing is when trying to order by some attribute from person table, if I do
order: {
anyColumnFromTypePersonHere: 'ASC' | 'DESC'
}
It works pretty fine, but if I want to order by status (that is an attribute from person) it will not work
Just add this line:
qb.addOrderBy('person.status', "ASC") ;

Import large amounts of data, but do a .find() for each element

I have a collection of customers of 60.000 items. I need to import a list of people, of 50.000. But for each person, I need to find the ID of the customer and add that to the object that is being inserted.
How should this be done most efficently?
export default async ({ file, user, database }: Request, res: Response) => {
try {
const csv = file.buffer.toString("utf8");
let lines = await CSV({
delimiter: "auto" // delimiter used for separating columns.
}).fromString(csv);
let count = {
noCustomer: 0,
fails: 0
};
let data: any = [];
await Promise.all(
lines.map(async (item, index) => {
try {
// Find customer
const customer = await database
.model("Customer")
.findOne({
$or: [
{ "custom.pipeID": item["Organisasjon - ID"] },
{ name: item["Person - Organisasjon"] }
]
})
.select("_id")
.lean();
// If found a customer
if (!isNil(customer?._id)) {
return data.push({
name: item["Person - Navn"],
email: item["Person - Email"],
phone: item["Person - Telefon"],
customer: customer._id,
updatedAt: item["Person - Oppdater tid"],
createdAt: item["Person - Person opprettet"],
creator: users[item["Person - Eier"]] || "5e4bca71a31da7262c3707c5"
});
}
else {
return count.noCustomer++;
}
} catch (err) {
count.fails++;
return;
}
})
);
const people = await database.model("Person").insertMany(data)
res.send("Thanks!")
} catch (err) {
console.log(err)
throw err;
}
};
My code just never sends an response If I use this as a Express request.

GraphQL with RESTful returning empty response

I am connecting GraphQL with REST endpoints, I confirmed that whenever I am calling http://localhost:3001/graphql it is hitting REST endpoint and it is returning JSON response to GraphQL server, but I am getting an empty response from GraphQL server to GUI as follows:
{
"data": {
"merchant": {
"id": null
}
}
}
Query (decoded manually):
http://localhost:3001/graphql?query={
merchant(id: 1) {
id
}
}
Below is how my GraphQLObjectType looks like:
const MerchantType = new GraphQLObjectType({
name: 'Merchant',
description: 'Merchant details',
fields : () => ({
id : {
type: GraphQLString // ,
// resolve: merchant => merchant.id
},
email: {type: GraphQLString}, // same name as field in REST response, so resolver is not requested
mobile: {type: GraphQLString}
})
});
const QueryType = new GraphQLObjectType({
name: 'Query',
description: 'The root of all... queries',
fields: () => ({
merchant: {
type: merchant.MerchantType,
args: {
id: {type: new GraphQLNonNull(GraphQLID)},
},
resolve: (root, args) => rest.fetchResponseByURL(`merchant/${args.id}/`)
},
}),
});
Response from REST endpoint (I also tried with single object in JSON instead of JSON array):
[
{
"merchant": {
"id": "1",
"email": "a#b.com",
"mobile": "1234567890"
}
}
]
REST call using node-fetch
function fetchResponseByURL(relativeURL) {
return fetch(`${config.BASE_URL}${relativeURL}`, {
method: 'GET',
headers: {
Accept: 'application/json',
}
})
.then(response => {
if (response.ok) {
return response.json();
}
})
.catch(error => { console.log('request failed', error); });
}
const rest = {
fetchResponseByURL
}
export default rest
GitHub: https://github.com/vishrantgupta/graphql
JSON endpoint (dummy): https://api.myjson.com/bins/8lwqk
Edit: Adding node.js tag, may be issue with promise object.
Your fetchResponseByURL function get empty string.
I think the main problem is that you are using wrong function to get the your JSON string, please try to install request-promise and use it to get your JSON string.
https://github.com/request/request-promise#readme
something like
var rp = require('request-promise');
function fetchResponseByURL(relativeURL) {
return rp('https://api.myjson.com/bins/8lwqk')
.then((html) => {
const data = JSON.parse(html)
return data.merchant
})
.catch((err) => console.error(err));
// .catch(error => { console.log('request failed', error); });
}
In this case using data.merchant solved my problem. But the above suggested solution i.e., use of JSON.parse(...) might not be the best practice because if there are no object in JSON, then expected response might be as follows:
{
"data": {
"merchant": null
}
}
Instead of fields to be null.
{
"data": {
"merchant": {
"id": null // even though merchant is null in JSON,
// I am getting a merchant object in response from GraphQL
}
}
}
I have updated my GitHub: https://github.com/vishrantgupta/graphql with working code.

GraphQL - passing an ObjectType a parameter

I'm using GraphQL and it's working great, however, I can't seem to figure out how to pass a parameter into the fields section of my Event GraphQLObjectType.
I would like to be able to pass in the currentUserId (which is given to me through a token) into the Event GraphQLObjectType so I can add in an isAttending attribute.
I've attached code with comments of what I'm basically trying to do:
const Event = new GraphQLObjectType({
name: 'Event',
description: 'This represents an Event',
fields: (currentUserId) => { // currentUserId is the parameter I would like to pass in
return {
id: {
type: GraphQLInt,
resolve (event) {
return event.id;
}
},
title: {
type: GraphQLString,
resolve (event) {
return event.title;
}
},
attendees: {
type: new GraphQLList(User),
resolve (event) {
return event.getAttendees()
}
},
// this is what I would like to do
isAttending: {
type: GraphQLBool,
resolve (event) {
return event.getAttendees({
where: {
id: currentUserId // that's the parameter I would like pass in
}
}).then(attendee => {
return (attendee.length > 0 ? true : false);
)};
}
}
// end of what I'm trying to do //
};
}
});
const Query = new GraphQLObjectType({
name: 'Query',
description: 'Root query object',
fields: () => {
return {
events: {
type: new GraphQLList(Event),
args: {
id: {
type: GraphQLInt
}
},
resolve (root, args) {
// here is the parameter I would like to pass to the event object
let currentUserId = root.userId;
////////
return Db.models.event.findAll({ where: args });
}
},
...
Update
The reason I can't just do data.currentUserId = root.userId, is because it's not visible when I'm returned a collection of event objects, since what is passed into my Event GraphQLOBjectType is only the {event} object.
What it looks like when I do data.currentUserId and there is an array of objects inside data is this:
[{objects}, currentUserId: 1]
As opposed to what we want which is this:
[{object, currentUserId: 1}, {anotherObject, currentUserId: 1}]
If I wanted to have access to the currentUserId in the Event GraphQLObject, the only thing I can think of is to loop through every object and add the currentUserId onto it like this:
return events.map(event => {
event.currentUserId = currentUserId;
return event;
});`
Is this the best solution?
I'm afraid you can't do that. fields doesn't recieve any parameters, so you won't send any either.
Fortunately, you can achieve that in more convenient way.
Everything your parent type (Query) returns in resolve function is visible in child resolve's root parameter.
const Query = new GraphQLObjectType({
name: 'Query',
description: 'Root query object',
fields: () => ({
events: {
type: new GraphQLList(Event),
args: {
id: {
type: GraphQLInt
}
},
resolve (root, args) {
return Db.models.event.findAll({ where: args })
.then(data => {
// pass the parameter here
data.currentUserId = root.userId;
return data;
});
}
},
...
Then your Event object would look like this:
const Event = new GraphQLObjectType({
name: 'Event',
description: 'This represents an Event',
fields: () => ({
...
isAttending: {
type: GraphQLBool,
resolve: (event) => {
return event.getAttendees({
where: {
id: event.currentUserId // that's the parameter you've passed through parent resolve
}
}).then(attendee => {
return (attendee.length > 0 ? true : false);
});
}
}
})
});

Resources