sails: convert field in sql query to json - sails.js

I have a query like this:
var sql = "select * from a left join b where a.id in (select field from c)";
Model.query(sql, function (err, result) {
return res.json({data:result});
});
which return result something like this:
{
"data": [
{
"field1": "[\"element 1\", \"element 1\"]",
...
}
]
}
you can see that "[\"element 1\", \"element 1\"]" is string and i don't like that. i want them to bo json. so the result should something like this:
{
"data": [
{
"field1": [\"element 1\", \"element 1\"],
...
}
]
}
how can i achieve that?

If your query represents something like a many-to-many relation, you could have a look at the .populate() function.
Otherwise you could do it like so:
var data = [{
"field1": "[\"element 1\", \"element 2\"]",
"field2": "[\"element 1\", \"element 2\"]",
}];
var parsedData = [];
data.forEach(function(item, index) {
var parsed = {};
for (var fieldName in item) {
try {
parsed[fieldName] = JSON.parse(item[fieldName]);
} catch (e) {
parsed[fieldName] = [];
}
}
parsedData.push(parsed);
});
console.log(parsedData);

Related

MongoDB query for nested elements on each level

I have to find all documents in collection, also those nested, by one field that all of them have (common_field). In xpath it would be something like this: //*[#common_field='value']. How to do something like this in mongo?
{
"_id": ObjectId(
"5e3800700045c500cecffb00"
),
"common_field": "100281",
"other_field": "other",
"A": {
"common_field": "313000000",
"a_field": "a"
},
"B": {
"common_field": "213125",
"b_field": "bb",
"B": {
"common_field": "543534",
"b_field": "b"
},
"C": {
"common_field": "312312",
"c_field": "c"
}
}
}
I don't think you can achieve it natively with the Aggregation framework, you have to write a recursive function. This one should work:
var CheckField = function (doc, fieldName, value) {
var ret = false;
Object.keys(doc).forEach(function (key) {
if (key == fieldName && doc[key] == value) {
ret = true;
} else {
if (typeof doc[key] == "object")
ret = ret || CheckField(doc[key], fieldName, value);
}
});
return ret;
};
Then use the function like this:
var ObjIds = []
db.col.find({}).forEach(function (myDoc) {
if (CheckField(myDoc, "common_field", "313000000"))
ObjIds.push(myDoc._id);
})
Either print documents directly of use returned array as query filter:
db.col.find({ _id: { $in: ObjIds } })

sum value and remove duplicates in List

I have this list and want to sum value and remove duplicates in List
1 - check of productName
2 - sum NumberOfItems if productName equals
For Example :
"Orders":[
{
"productName":"Apple",
"NumberOfItems":"5"
},
{
"productName":"Orange",
"NumberOfItems":"2"
},
{
"productName":"Egg",
"NumberOfItems":"5"
},
{
"productName":"Apple",
"NumberOfItems":"3"
},
{
"productName":"Orange",
"NumberOfItems":"4"
},
{
"productName":"Egg",
"NumberOfItems":"9"
},
]
The result I need look like this result : (Sum Depend on productName)
"Orders":[
{
"productName":"Apple",
"NumberOfItems":"8"
},
{
"productName":"Orange",
"NumberOfItems":"6"
},
{
"productName":"Egg",
"NumberOfItems":"14"
},
]
final orders = data["Orders"] as List;
final mapped = orders.fold<Map<String, Map<String, dynamic>>>({}, (p, v) {
final name = v["productName"];
if (p.containsKey(name)) {
p[name]["NumberOfItems"] += int.parse(v["NumberOfItems"]);
} else {
p[name] = {
...v,
"NumberOfItems": int.parse(v["NumberOfItems"])
};
}
return p;
});
final newData = {
...data,
"Orders": mapped.values,
};
print(newData);
Result is:
{Orders: ({productName: Apple, NumberOfItems: 8}, {productName: Orange, NumberOfItems: 6}, {productName: Egg, NumberOfItems: 14})}
Notice: This code has 2 loop which means slower.
Igor Kharakhordin answered smarter one, but may be difficult for those who ask this question.(since he is doing two things at once.) Basically I am doing same thing.
String string = await rootBundle.loadString("asset/data/Orders.json");
Map orders = jsonDecode(string);
List orderList = orders["Orders"];
Map<String,int> sums = {};
for(int i = 0 ; i < orderList.length; i++){
dynamic item = orderList[i];
if(sums.containsKey(item["productName"])){
sums[item["productName"]] += int.parse(item["NumberOfItems"]);
}
else{
sums[item["productName"]] = int.parse(item["NumberOfItems"]);
}
}
List sumList = [];
sums.forEach((key,value)=>
sumList.add({
"productName":key,
"NumberOfItems":value.toString()
})
);
Map result = {
"Orders":sumList
};
print(jsonEncode(result));
Result
{
"Orders": [
{
"productName": "Apple",
"NumberOfItems": "8"
},
{
"productName": "Orange",
"NumberOfItems": "6"
},
{
"productName": "Egg",
"NumberOfItems": "14"
}
]
}

Insert Multiple records in dynamodb using api gateway

How can I insert multiple rows in dynamodb using body mapping template of API gateway?
Input to my code is "xyz 1,abc 2" which has information about 2 rows to be inserted.
Only second record which is "abc 2" is getting stored, I want both records to be inserted in the table. Below is the code I have written
#set($rawAPIData = $input.path('$'))
#set ($bulk = $rawAPIData.split(","))
{
"TableName": "tablename",
#foreach( $records in $bulk)
#set ($s = $records.split(" "))
"Item": {
"col1": {
"S": "$s.get(0)"
},
"col2": {
"S": "$s.get(1)"
}
}
#if( $foreach.hasNext ), #end
#end
}
I'm new to this, suggestion would really help
This AWS guide shows how to use API Gateway as a proxy for DynamoDB. It's similar the approach you are trying to take. As a suggestion, it might be better have your api focus on a single row at a time, rather than splitting multiple inputs on ,. For example it would simplify your template somewhat to send requests similar to those found in the guide.
Example Request Body:
{
"col1": "xyz",
"col2": "1"
}
Template (derived from your template code):
{
"TableName": "tablename",
"Item": {
"col1": {
"S": "$input.path('$.col1')"
},
"col2": {
"S": "$input.path('$.col2')"
}
}
}
However, if you want to stick to operating on multiple items, The BatchWriteItem documentation would be worth a read. Following the example, I think this should be your body template:
#set($rawAPIData = $input.path('$'))
#set ($bulk = $rawAPIData.split(","))
{
"RequestItems": {
"tablename": [
#foreach($records in $bulk)
#set ($s = $records.split(" "))
{
"PutRequest": {
"Item": {
"col1": {
"S": "$s.get(0)"
},
"col2": {
"S": "$s.get(1)"
}
}
}
}
#if( $foreach.hasNext ),
#end
]
}
#end
}
I used the similar approach as #Gerand, but I solved it using lambda. Here is the working code:
'use strict';
const AWS = require("aws-sdk");
const dynamodb = new AWS.DynamoDB();
exports.handler = (event, context, callback) => {
var data=event.data;
var bulk = data.split(",");
var toSave = [];
for(var i = 0; i < bulk.length; i++) {
var s=bulk[i].split(" ");
var item = {
"col1": {
S: s[0]
},
"col2": {
S: s[1]
}
};
toSave.push(item);
}
var items = [];
for(var i = 0; i < toSave.length; i++) {
items[i] = {
PutRequest: { Item: toSave[i] }
}
}
var params = {
RequestItems: {
'table_name': items
}
};
dynamodb.batchWriteItem(params, function(err, data) {
console.log("Response from DynamoDB");
if(err) console.log(err);
else console.log(data);
});
};

MongoDB - Many counts using an array

How to make many counts using an array as input in Mongoose, and return an array
I am trying to use the code below but it is not working, list2 is returning as empty.
list = ['Ann', 'Bob', 'John', 'Karl'];
list2 = [];
for(let i = 0; i < list.length; i++) {
Clients.count({name: list[i]}, function(err, doc){
list2.push(doc);
})
}
return list2
You could run an aggregation pipeline as follows:
list = ['Ann', 'Bob', 'John', 'Karl'];
list2 = [];
Clients.aggregate([
{ "$match": { "name": { "$in": list } } },
{
"$group": {
"_id": "$name",
"count": { "$sum": 1 }
}
},
{
"$group": {
"_id": null,
"list2": {
"$push": {
"name": "$_id",
"count": "$count"
}
}
}
}
]).exec(function(err, results) {
list2 = results[0].list2;
console.log(list2);
});
const async = require('async');
var list = ['Ann', 'Bob', 'John', 'Karl'];
async.map(list, function(item, callback) {
result = {};
Clients.count({name: item}, function(err, data) {
result[item] = data || 0;
return callback(null, result);
});
}, function(err, data) {
console.log(data);
});
Here's another way based on Med Lazhari's answer
const async = require('async');
var list = ['Ann', 'Bob', 'John', 'Karl'];
var counting = function (item, doneCallback) {
var query = Clients.count({name: item});
query.then(function (doc) {
return doneCallback(null, doc);
});
};
async.map(list, counting, function(err, data) {
console.log(data);
});

How can I find documents in a collection based on array values

I tried adding a helper to return array with documents, which looks like:
documents = {
realPlayers: [],
subscribers: [
{playerId: },
{playerId: },
{playerId: }
],
privatGame:,
gameType:,
gameStatus: 'active'
}
I tried this, but it doesn't work (forEach too):
Template.myGames.helpers({
'myGames': function() {
let gamePul = [],
activeGames = Games.find({gameStatus: "active"});
for (var i = 0; i < activeGame.length; i++) {
if (activeGame[i].subscribers) {
for (var j = 0; j < activeGame[i].subscribers.length; j++) {
if (activeGame[i].subscribers[j].playerId = Meteor.userId()) gamePul.push(activeGame[i]);
}
}
};
return gamePul;
}
});
You're just trying to find the set of games the current user is a subscriber to right? You just need $elemMatch in your query:
Template.myGames.helpers({
myGames: function() {
return Games.find({ gameStatus: "active",
subscribers: { $elemMatch: { playerId: Meteor.userId() }}});
}
});
docs