I need to do a join query on firebase using elasticsearch,
can anyone help me?
In particular I have two nodes, in the child node I have a field that is the id of the father node and I would like to have as a result all the fields of the father node.
How do I build my index in the code?
In adding, in my client I use elasticsearchclient,
here is an extract of the code to index a node:
var db = admin.database();
var etest = db.ref(type);
etest.on('child_added', createOrUpdateIndex);
etest.on('child_changed', createOrUpdateIndex);
etest.on('child_removed', removeIndex);
function createOrUpdateIndex(snap) {
client.index(index, type, snap.val(), snap.key)
.on('data', function(data) { console.log('indexed', snap.key + data ); })
.on('error', function(err) { console.log('index error ', err); }).exec();
}
function removeIndex(snap) {
client.deleteDocument(index, type, snap.key, function(error, data) {
if( error ) console.error('failed to delete', snap.key, error);
else console.log('deleted', snap.key);
});
}
And to take query results:
var queue = db.ref("search");
queue.child('request').on('child_added', processRequest);
function processRequest(snap) {
console.log('process...... ');
snap.ref.remove(); // clear the request after we receive it
var data = snap.val();
// Query ElasticSearch
client.search(index, data.type, { "query": { 'query_string': {
"query" : data.query
}}})
.on('data', function(results) {
var res = JSON.parse(results);
console.log(JSON.stringify(res.hits));
console.log("TOTAL " + JSON.stringify(res.hits.total));
queue.child('response/'+snap.key).set(results);
})
.on('error', function(error){ console.log("errore"); }).exec();
}
Thank you in advance
There are two ways to store your data.
First is creating a nested doc. This is helpful if you need to perform search on some of the values and need other info only for the display.
PUT /my_index {
"mappings": {
"yourIndex": {
"properties": {
"yourColumn": {
"type": "nested",
"properties": {
"name": { "type": "string" },
"parentNode": { "type": "string" },
"childNode": { "type": "string" }
}
}
}
}}}
Eg.
'str1', 'parent1', 'child1'
'str2' 'parent1', 'child2'
If you need not maintain any hierarchy,
you can simply create 3 separate columns and store like a flat data.
You can specify parent1 id and search for all the docs in both the cases.
Related
{
"chats": {
"3q7QDEHAVpU3DhiNyAOKlZY7L0S25rAQ6mD63HRiygVytCutjMfyZr43": {
"messages": {
"-MhP9vpwRKLND9tIBBOT": {
"message": "thanks",
"senderId": "5rAQ6mD63HRiygVytCutjMfyZr43",
"timeStamp": 1629305419888
},
"-MhSZ8z1kObr2W0UOdZK": {
"message": "hello",
"senderId": "3q7QDEHAVpU3DhiNyAOKlZY7L0S2",
"timeStamp": 1629362363332
},
}
},
"3q7QDEHAVpU3DhiNyAOKlZY7L0S2Ud9F8Ke4bZTMu9vMf5GF98jnwng2":
{},
"5rAQ6mD63HRiygVytCutjMfyZr433q7QDEHAVpU3DhiNyAOKlZY7L0S2":
{},
}
}
I want to retrieve data from the real time database but due to unnamed nodes I am not able to capture the data. Please help me?
When I run the function I getting null in console.log:
Path is correct but snapshot shown null in console:
snapshot: null
function selectAllData6() {
var Id1 = this.id;
var Path1 = firebase.database().ref("chats/{senderId}/messages/{receiverId}/message");
Path1.on('value', function(snapshot) {
var message = snapshot.val();
console.log("message: " + message);
console.log("Path1: " + Path1);
console.log("snapshot: " + snapshot.val());
});
}
selectAllData6();
I have this data i have held in this variable this.roomsData.room_photos
[ { "url": "https://api.example.com/uploads/609ee58907166.jpg" }, { "url": "https://api.example.com/uploads/609ee5898ba19.jpg" }, { "url": "https://api.example.com/uploads/609ee58994a10.jpg" }, { "url": "https://api.example.com/uploads/609ee589af635.jpg" }, { "url": "https://api.example.com/uploads/609ee589b0fc7.jpg" }, { "url": "https://api.example.com/uploads/609ee589cd79f.jpg" }, { "url": "https://api.example.com/uploads/609ee589d8d27.jpg" } ]
and this data
[ { "url": "https://api.example.com/uploads/609eeded64530.jpg" }, { "url": "https://api.example.com/uploads/609eeded68ebe.jpg" }, { "url": "https://api.example.com/uploads/609eeded6a6bc.jpg" } ]
i have in this variable this.roomsData.edit_room_photos and its being generated from
uploadRoomImages: async function (file, progress, error, options) {
try {
console.log(file, options);
const formData = new FormData()
formData.append('room_photos', file)
const result = await fetch('https://api.example.com/uploads_scripts/rooms.php', {
method: 'POST',
body: formData
})
progress(100) // (native fetch doesn’t support progress updates)
return await result.json()
} catch (err) {
error('Unable to upload file')
}
},
and this is the component
<FormulateInput
type="image"
name="room_photos"
v-model="roomsData.edit_room_photos"
label="Select Room Images To Upload"
help="Select a png, jpg,webp or gif to upload."
validation="required|mime:image/jpeg,image/png,image/gif,image/webp"
:uploader="uploadRoomImages"
error-behavior="live"
multiple
/>
Since there is data already in this variable this.roomsData.room_photos , how can i add the data in this variable this.roomsData.room_photos
to data i get from waiting for my function to resolve and store the data here this.roomsData.edit_room_photos
I have tried object assign and array concat on the form submit handler but that results to cyclic json errors.
I want to add the data in the two arrays together without removing the duplicates. How can i combine the two arrays together without removing duplicates.
You can use a computed value with a setter:
computed: {
room_photos: {
get: function () {
return [...this.roomsData.room_photos, ...this.roomsData.edit_room_photos];
},
set: function (newValue) {
this.roomsData.edit_room_photos = newValue.slice(this.roomsData.room_photos.length);
},
},
},
If the result of uploadRoomImages() leads to the value of roomsData.edit_room_photos, you could just modify the return value of uploadRoomImages() to .concat the other array:
uploadRoomImages: async function (file, progress, error, options) {
try {
//...
const result = await result.json()
return result.concat(this.roomsData.room_photos)
} catch (err) {
error('Unable to upload file')
}
},
Note Array.prototype.concat() does not filter out duplicates, so there's no need to be concerned about losing duplicate entries in this case.
I am trying to say:
select * from myTable where pkName in ('john', 'fred', 'jane')
but there doesn't seem to be a native way to feed a list of items in an array. I have my query working and retrieving values for a single primary key but want to be able to pass in multiple ones. It seems this isn't possible from looking at the DynamoDb page in the console but is there a good workaround? Do I just have multiple OR in my KeyConditionExpression and a very complex ExpressionAttributeValues?
I'm referencing this page:
https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html
And using code based on the following (which can be found at the address below):
var params = {
ExpressionAttributeValues: {
':s': {N: '2'},
':e' : {N: '09'},
':topic' : {S: 'PHRASE'}
},
KeyConditionExpression: 'Season = :s and Episode > :e',
ProjectionExpression: 'Title, Subtitle',
FilterExpression: 'contains (Subtitle, :topic)',
TableName: 'EPISODES_TABLE'
};
https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/dynamodb-example-query-scan.html
You are looking for the batchGetItem function, documented here.
You can also use DocumentClient and batchGet.
const AWS = require('aws-sdk');
const dbClient = new AWS.DynamoDB.DocumentClient({ region: 'ap-south-1' });
exports.handler = (event, context, callback) => {
var cartItems=JSON.parse(event.body);
let scanningtable = {
RequestItems: {
COOLERS : {
Keys: [
{
"ITEM_ID": 379
},
{
"ITEM_ID": 376
}
],
ProjectionExpression: "ITEM_ID, #N,CATEGORY, SUB_CATEGORY, BRAND, SELL_RATE",
ExpressionAttributeNames: {
"#N": "NAME"
},
}
}
};
dbClient.batchGet(scanningtable, function (err, data) {
if (err) {
callback(err, null);
} else {
var response = {
"statusCode": 200,
"headers": {
"Access-Control-Allow-Origin": "*"
},
"body": JSON.stringify(data),
};
callback(null, response);
}
});
};
I'm trying to update the JSON field "champ_x" from 1 to 3 and for both players 1 at a time in a dynamic function:
{
"_id": {
"$oid": "58a3521edf127d0a0c417cda"
},
"room": "room_0.0940045412694186",
"player_1": "eee",
"player_2": "fff",
"player_1_details": {
"history_moves": [],
"champions": [
{
"champ_1": "na"
},
{
"champ_2": "na"
},
{
"champ_3": "na"
}
]
},
"player_2_details": {
"history_moves": [],
"champions": [
{
"champ_1": "na"
},
{
"champ_2": "na"
},
{
"champ_3": "na"
}
]
},
"game_state": "789",
"__v": 0
}
I've got this model:
match_schema.statics.update_champ = function(room, turn, champ_num, champ_select, callback){
if(champ_num == "champ_1"){
match_mongoose.update({ room: room }, { $set: { 'player_1_details.champions.0.champ_1': champ_select}})
.exec(function(error){
if(error){ return callback(error); }else{ return callback(null); }
});
}
};
This model works fine
My problem is, I'm trying to make it dynamic, in which I can just send through the function parameters the current turn(1 or 2), and the chosen position(champ_1,2, or 3).
I've tried this:
//Update Champion
match_schema.statics.update_champ = function(room, turn, champ_num, champ_select, callback){
match_mongoose.update({ room: room }, { $set: { 'player_'+turn+'_details.champions.0.'+champ_num: champ_select}})
.exec(function(error){
if(error){ return callback(error); }else{ return callback(null); }
});
};
var match_mongoose = mongoose.model('matches', match_schema, 'matches');
module.exports = match_mongoose;
But I get an error that says the "Unexpected token +" seems like concatenating the value doesn't work. Is there a way to do this?
Thanks!
You may build the $set modifier and the match part as suggested by #dNitro :
var modifier = { $set: {} };
modifier.$set['player_' + turn + '_details.champions.$.champ_' + champ_num] = champ_select;
You will have also an issue with array index, you specify champions.0 so it will always take the first array item which won't match for champs_2 & champs_3. One solution for this is to use positional parameter $ with a match from the array :
var match = {};
match['room'] = room;
match['player_' + turn + '_details.champions.champ_' + champ_num] = { $exists: true };
The full update function is :
matchSchema.statics.update_champ = function(room, turn, champ_num, champ_select, callback) {
var modifier = { $set: {} };
modifier.$set['player_' + turn + '_details.champions.$.champ_' + champ_num] = champ_select;
var match = {};
match['room'] = room;
match['player_' + turn + '_details.champions.champ_' + champ_num] = { $exists: true };
this.update(match, modifier)
.exec(function(error) {
if (error) {
return callback(error);
} else {
return callback(null);
}
});
};
And calling it with :
Match.update_champ("room_0.0940045412694186", 1, 1, "new_value", function(err, res) {
if (!err) {
console.log(err);
return;
}
console.log(res);
});
You can find a full example here
I am parsing a CSV file and putting the data in a table with AWS DynamoDB.
As it stands right now, I am getting the following error:
One or more parameter values were invalid: An AttributeValue may not contain an empty string
... BEFORE it puts the data in the table. The data is getting to the table, but not before spamming me with that error a million times.
My Code:
var csv = require("fast-csv");
csv.fromPath(file, {
headers: true,
ignoreEmpty: true
})
.on("data", function(data) {
for (var key in data) {
if (data.hasOwnProperty(key)) {
if (data[key] === "" || data[key] === undefined || data[key] === null) {
data[key] = "N/A";
}
}
params = {
TableName: tableName,
Item: {
RefID: {
S: data["Ref-ID"]
},
//lots of other data
}
};
dynamodb.putItem(params, function(err, data) {
if (err) {
console.error("Unable to add item. Error JSON:", JSON.stringify(err, null, 2));
}
else {
console.log("Added item:", JSON.stringify(data, null, 2));
}
});
}
})
.on("end", function() {
console.log("done");
});
As you can see, I am converting any possible empty strings to == N/A in an attempt to solve this problem. Any thoughts?
EDIT:
This turns out to be undefined when it should display what it put in the table.
console.log("Added item:", JSON.stringify(data[key], null, 2));
EDIT 2: Changed this code...
dynamodb.putItem(params, function(err, data)
...to this:
dynamodb.putItem(params, function(err, info)
I am still getting the errors, but am now displaying the table correctly.
It appears that dynamoDB at this time does not allow empty strings. I can NOT understand why, but as of this date you cannot not store an attribute of "Key":"".
Please complain to amazon about it. key="" and key=null are very different use cases and are needed.
Try doing field validation on your param.Item Object to verify that everything is set properly; and find the errornous fields that are plaguing your console.
var tableName = "wombat_habitats";
var data = {
"Ref-ID": "Charlie"
};
params = {
TableName: tableName,
Item: {
RefID: {
S: data["Ref-ID"]
},
SomethingElse: {
S: data["Bad-Key"]
}
//lots of other data
}
};
for(var itemKey in params.Item) {
for(var itemAttr in params.Item[itemKey]) {
var value = params.Item[itemKey][itemAttr];
if(value === undefined || value === "") {
console.log("item", itemKey, "of type", itemAttr, "is undefined!")
}
}
}