sum value and remove duplicates in List - flutter

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"
}
]
}

Related

Group by and Get Max Value MongoDb

I would like to get the highest number of counts for each numId and display it on my front end in a table.
Here is an example of my database:
{
"_id": {
"$oid": "6294777f677b4c647e28771a"
},
"numId": "5",
"respondee": "0x9d95bcaa5b609fa97a7ec860bec115aa94f85ba9",
"__v": 0,
"originalResponse": "test2",
"submittedAt": {
"$date": {
"$numberLong": "1653897087357"
}
},
"addresses": [
"0x39c878a3df98002ddba477a7aa0609fb5a27e2ff",
"0xe3342d6522ad72f65d6b23f19b17e3fb12161f90"
],
"count": 2
},
{
"_id": {
"$oid": "6294836e677b4c647e287e93"
},
"numId": "5",
"respondee": "0xe3342d6522ad72f65d6b23f19b17e3fb12161f90",
"__v": 0,
"originalResponse": "test3",
"submittedAt": {
"$date": {
"$numberLong": "1653900142375"
}
},
"addresses": [
],
"count": 0
}
I have written something like this but I'm not sure how to group the results according to the numId
import Response from '../../../models/Response.model';
import db from '../../../utils/config/db';
import nc from 'next-connect';
import { onError } from '../../../utils/error';
const handler = nc({
onError,
});
//GET all
handler.get(async (req, res) => {
await db.connect();
let responses = await Response.find({ });
//To group responses by numId
// Sort responses by votes in ascending order
responses = responses.sort((a, b) => {
return a.count - b.count;
});
let topResponses = responses.filter((response) => {
return response.count === responses[0].count;
});
// Check if respondee has the highest count response
if (
topResponses.length > 0 &&
topResponses.find((response) => {
return response.respondee === respondee;
})
) {
// Get the response
let response = topResponses.find((response) => {
return response.respondee === respondee;
});
// Get the response
let responseString = response.response;
// Get the count
let count = response.count;
}
await db.disconnect();
});
export default handler;
I have figured out the answer by referring from another stackoverflow:
Group by and Get Max Value MongoDb
let responses = await Response.aggregate([
{ $sort: { votes: -1 } },
{ $group: { _id: '$baseId', group: { $first: '$$ROOT' } } },
{ $replaceRoot: { newRoot: '$group' } },
]);
res.send(responses);

Promise all in typescript does not resolve all

In my code I need to update the model
{
"customerCode": "CUS15168",
"customerName": "Adam Jenie",
"customerType": "Cash",
"printPackingSlip": "true",
"contacts": [
{
"firstName": "Hunt",
"lastName": "Barlow",
"email": "huntbarlow#volax.com",
"deliveryAddress": "805 Division Place, Waumandee, North Carolina, 537",
},
{
"firstName": "Barlow",
"lastName": "Hunt",
"email": "huntbarlow#volax.com",
"deliveryAddress": "805 Division Place, Waumandee, North Carolina, 537",
}
],
"deliveryAddress": [
{
"addressName": "Postal",
"addressType": "postal address",
"addressLine1": "plaza street",
"addressLine2": "broome street",
"suburb": "Guilford",
"city": "Oneida",
"state": "Colorado",
"postalCode": "3971",
"country": "Belarus",
"deliveryInstruction": "test delivery address"
},
{
"addressName": "Physical",
"addressType": "physical address",
"addressLine1": "plaza street",
"addressLine2": "broome street",
"suburb": "Guilford",
"city": "Oneida",
"state": "Colorado",
"postalCode": "3971",
"country": "Belarus",
"deliveryInstruction": "test delivery address"
}
]
}
I used promise all to achieve that. In postman, I send this object, but first it needs to add the customer, the contact array and then delivery address array. I did it as follows.
public async createCustomer(customer: CustomerDTO): Promise<CustomerDTO> {
let deliveryAddress = [];
let contacts = [];
let customerDto = new CustomerDTO();
customerDto.customerCode = customer.customerCode;
customerDto.tenantId = customer.tenantId;
if (customer.contacts.length > 0) {
customer.contacts.map((element => {
contacts.push(element);
}));
customer.contacts.length = 0;
}
if (customer.deliveryAddress.length > 0) {
customer.deliveryAddress.map((element => {
deliveryAddress.push(element);
}));
customer.deliveryAddress.length = 0;
}
const createdCustomer = await this.customerRepo.updateOrCreateCustomer(customer);
let updatedAddress = deliveryAddress.map(async (address: CustomerDeliveryAddressDto) => {
return await this.customerRepo.updateDeliveryAddress(address, customerDto, address._id);
});
let updatedContacts = contacts.map(async (contact: CustomerContactsDto) => {
return await this.customerRepo.createOrUpdateContactList(contact, customerDto, contact._id);
});
return Promise.all([updatedAddress, updatedContacts]).
then((results: [Promise<boolean>[], Promise<boolean>[]]) => {
console.log(results);
return this.customerRepo.getLastUpdatedCustomer();
}).
then((result) => {
return result;
}).
catch(e => {
console.error(e);
return e;
});
}
In customerRepository
public async updateDeliveryAddress(deliveryAddressDto: CustomerDeliveryAddressDto, customerDto: CustomerDTO, deliveryAddressId: string): Promise<boolean> {
const customerToBeUpdated = await this.model.findOne({
customerCode: customerDto.customerCode,
tenantId: customerDto.tenantId
});
if (customerToBeUpdated !== null) {
if (deliveryAddressId != null || deliveryAddressId != undefined) {
const result = await this.model.findOneAndUpdate({ _id: customerToBeUpdated._id, deliveryAddress: { $elemMatch: { _id: deliveryAddressId } } },
{
$set: {
//code here
}
},
{ 'new': true, 'safe': true, 'upsert': true });
if (result){
return true;
}
} else {
const result = await this.model.findOneAndUpdate({ _id: customerToBeUpdated._id },
{
$push: { deliveryAddress: deliveryAddressDto }
},
{ 'new': true, 'safe': true, 'upsert': true }
);
if (result) {
return true;
}
}
} else {
return false;
}
}
The problem is that it does not resolve all the methods when it goes to promise all method and I need to get the last updated customer, but it gives the result DeliveryAddress and contacts with empty arrays. Customer document on mongodb is updated as needed.
You need to pass the promises directly in a flat array.
Promise.all on MDN
If the iterable contains non-promise values, they will be ignored, but still counted in the returned promise array value (if the promise is fulfilled)
You can do this easily using the spread operator.
let updatedAddress = deliveryAddress.map(async (address: CustomerDeliveryAddressDto) => {
return await this.customerRepo.updateDeliveryAddress(address, customerDto, address._id);
});
let updatedContacts = contacts.map(async (contact: CustomerContactsDto) => {
return await this.customerRepo.createOrUpdateContactList(contact, customerDto, contact._id);
});
// need to give a flat array to Promise.all, so use the `...` spread operator.
return Promise.all([...updatedAddress, ...updatedContacts]).then(/* ... */
Also, since you are already using async / await, no reason you cannot await the Promise.all call.
const results = await Promise.all([...updatedAddress, ...updatedContacts]);
console.log(results);
return this.customerRepo.getLastUpdatedCustomer();
You can also nest Promise.all
let updatedAddress = Promise.all(deliveryAddress.map(async (address: CustomerDeliveryAddressDto) => {
return await this.customerRepo.updateDeliveryAddress(address, customerDto, address._id);
}));
let updatedContacts = Promise.all(contacts.map(async (contact: CustomerContactsDto) => {
return await this.customerRepo.createOrUpdateContactList(contact, customerDto, contact._id);
}));
return Promise.all([updatedAddress, updatedContacts])

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);
});

Sailsjs native with Mapreduce

I am working on sailsjs project, i just looking for suggestion to achieve the below output to make best performance with code samples.
My existing collection having this below document.
[{
"word" : "DAD",
"createdAt":"6/10/2016 7:25:59 AM",
"gamescore":1
},
{
"word" : "SAD",
"createdAt":"6/09/2016 7:25:59 AM",
"gamescore":1
},
{
"word" : "PAD",
"createdAt":"6/10/2016 8:25:59 AM",
"gamescore":1
}]
I need the below output which is something like this.
[{
"word" : "A",
"repeatedTimes" : "3",
"LatestRepeatedTime": "6/10/2016 8:25:59 AM"
},
{
"word" : "D",
"repeatedTimes" : "4",
"LatestRepeatedTime": "6/10/2016 8:25:59 AM"
},
{
"word" : "P",
"repeatedTimes" : "1",
"LatestRepeatedTime": "6/10/2016 8:25:59 AM"
},
{
"word" : "S",
"repeatedTimes" : "1",
"LatestRepeatedTime": "6/09/2016 8:25:59 AM"
}]
For the above scenario i implemented the below code to fetch, but it is not working at find query.
var m = function () {
var words = this.word;
if (words) {
for (var i = 0; i < words.length; i++) {
emit(words[i], 1);
}
}
}
var r = function (key, values) {
var count = 0;
values.forEach(function (v) {
count += v;
});
return count;
}
console.log(req.params.childid);
Activity.native(function (err, collection) {
console.log("hello");
collection.mapReduce(m, r, {
out: {merge: "words_count" + "_" + "575a4952bfb2ad01481e9060"}
}, function (err, result) {
Activity.getDB(function (err, db) {
var colname = "words_count" + "_" + "575a4952bfb2ad01481e9060";
var natCol = db.collection('words_count' + "_" + "575a4952bfb2ad01481e9060");
natCol.find({},..... **is not working**
natCol.count({}, function (err, docs) {
console.log(err);
console.log(docs);
res.ok(docs);
});
});
});
});
Answer:
natCol.aggregate([
{
$project:
{
_id: "$_id" ,
value:"$value"
}
}
], function(err, data){
console.log(data);
res.ok(data);
});
You could try the following
var m = function () {
if (this.word) {
for (var i = 0; i < this.word.length; i++) {
emit(this.word[i], {
"repeatedTimes": 1,
"LatestRepeatedTime": this.createdAt
});
}
}
};
var r = function (key, values) {
var obj = {};
values.forEach(function(value) {
printjson(value);
Object.keys(value).forEach(function(key) {
if (!obj.hasOwnProperty(key)) obj[key] = 0;
if (key === "repeatedTimes") obj[key] += value[key];
});
obj["LatestRepeatedTime"] = value["LatestRepeatedTime"];
});
return obj;
};
var opts = { out: {inline: 1} };
Activity.native(function (err, collection) {
collection.mapReduce(m, r, opts, function (err, result) {
console.log(err);
console.log(result);
res.ok(result);
});
});