Actually im new to mongoDB and mongoose, and im tryig to get nested join using three schemas and grouping them.
const company = Schema(
{
title: {type: String, required: true},
}
);
const plans = Schema(
{
companyId: {type: Schema.Types.ObjectId, ref: 'company', required: true},
title: {type: String, required: true},
}
);
const promotions = Schema(
{
planId: {type: Schema.Types.ObjectId, ref: 'plans', required: true},
title: {type: String, required: true},
}
);
I got the below result but separated, and I would like to group it, any help with this point would be appreciated?
[
{
_id: '621c2749ac447abf20a8a263',
title: 'test 1',
plans: {
_id: '621c290ad6bce1084f900b0b',
title: 'test 1',
promotions: {
_id: '621d1187b18de3c35fa3963b',
title: 'test 1',
},
},
},
{
_id: '621c2749ac447abf20a8a263',
title: 'test 2',
plans: {
_id: '621c290ad6bce1084f900b0b',
title: 'test 2',
promotions: {
_id: '621d1187b18de3c35fa3963d',
title: 'test 2',
},
},
},
];
The result that i want to achieve is:
[
{
title: 'company name',
plans: [
{
title:'plan name',
promotions: [
{
title:'promotion name'
}
]
},
...
]
},
...
]
A nested "$lookup" is one way to do it.
db.company.aggregate([
{
// lookup plans matching companies
"$lookup": {
"from": "plans",
"localField": "_id",
"foreignField": "companyId",
"pipeline": [
{
// lookup promotions matching plans
"$lookup": {
"from": "promotions",
"localField": "_id",
"foreignField": "planId",
"as": "promotions"
}
}
],
"as": "plans"
}
},
{
// drop unwanted fields
"$project": {
"_id": 0,
"plans._id": 0,
"plans.companyId": 0,
"plans.promotions._id": 0,
"plans.promotions.planId": 0
}
}
])
Try it on mongoplayground.net.
I have a heavy array like this:
[
{Id: 1, Name: 'Red', optionName: 'Color'},
{Id: 2, Name: 'Yellow', optionName: 'Color'},
{Id: 3, Name: 'Blue', optionName: 'Color'},
{Id: 4, Name: 'Green', optionName: 'Color'},
{Id: 7, Name: 'Black', optionName: 'Color'},
{Id: 8, Name: 'S', optionName: 'Size'},
{Id: 11, Name: 'M', optionName: 'Size'},
{Id: 12, Name: 'L', optionName: 'Size'},
{Id: 13, Name: 'XL', optionName: 'Size'},
{Id: 14, Name: 'XXL', optionName: 'Size'}
]
What I need to do is to group them by optionName and have two row in the main array like this:
[
{
Name: 'Color',
Data:[{Id: 1, Name: 'Red'},
{Id: 2, Name: 'Yellow'},
{Id: 3, Name: 'Blue'},
{Id: 4, Name: 'Green'},
{Id: 7, Name: 'Black'}]
}, {
Name: 'Size',
Data:[{Id: 8, Name: 'S'},
{Id: 11, Name: 'M'},
{Id: 12, Name: 'L'},
{Id: 13, Name: 'XL'},
{Id: 14, Name: 'XXL'}]
}
]
How to do it in javascript?
This is a snippet I wrote for these kind of situations. You can add this functionality to all of your arrays:
Object.defineProperty(Array.prototype, 'group', {
enumerable: false,
value: function (key) {
var map = {};
this.forEach(function (e) {
var k = key(e);
map[k] = map[k] || [];
map[k].push(e);
});
return Object.keys(map).map(function (k) {
return {key: k, data: map[k]};
});
}
});
You can use it like this. You can just pass a function which defines how you want to group your data.
var newArray = arr.group(function (item) {
return item.optionName;
});
Working Fiddle
If you need, you can replace {key: k, data: map[k]} with {Name: k, Data: map[k]}.
This is also more compact ES6 version of the code above:
Object.defineProperty(Array.prototype, 'group', {
enumerable: false,
value: function (key) {
let map = {};
this.map(e => ({k: key(e), d: e})).forEach(e => {
map[e.k] = map[e.k] || [];
map[e.k].push(e.d);
});
return Object.keys(map).map(k => ({key: k, data: map[k]}));
}
});
Use it like this:
let newArray = arr.group(item => item.optionName))
An ES6 solution using Map object:
function groupBy(arr, key) {
return arr.reduce(
(sum, item) => {
const groupByVal = item[key];
groupedItems = sum.get(groupByVal) || [];
groupedItems.push(item);
return sum.set(groupByVal, groupedItems);
},
new Map()
);
}
var Data = [
{ Id: 1, Name: 'Red', optionName: 'Color' },
{ Id: 2, Name: 'Yellow', optionName: 'Color' },
{ Id: 3, Name: 'Blue', optionName: 'Color' },
{ Id: 4, Name: 'Green', optionName: 'Color' },
{ Id: 7, Name: 'Black', optionName: 'Color' },
{ Id: 8, Name: 'S', optionName: 'Size' },
{ Id: 11, Name: 'M', optionName: 'Size' },
{ Id: 12, Name: 'L', optionName: 'Size' },
{ Id: 13, Name: 'XL', optionName: 'Size' },
{ Id: 14, Name: 'XXL', optionName: 'Size' } ];
document.getElementById("showArray").innerHTML =JSON.stringify([...groupBy(Data, 'optionName')], null, 4);
<pre id="showArray"></pre>
You can use reduce to get the resultset you need:
var result = list.reduce(function(memo, item) {
if (item.optionName === 'Color') {
memo[0].Data.push(
Id: item.Id,
Name: item.Name
});
}
if (item.optionName === 'Size') {
memo[1].Data.push({
Id: item.Id,
Name: item.Name
});
}
return memo;
}, [{ Name: 'Color', Data: [] }, { Name: 'Size', Data: [] }]);
variable list is your first list.
Hope this helps.
This is a snippet I wrote for kind of my situation in my application functionality of all arrays. This snippet code is use in node js application. All the above is is given solution but I was finding some problem in server side in node js.
This snippet is user full me....
var Data= [
{ Id: 1, Name: 'Red', optionName: 'Color' },
{ Id: 2, Name: 'Yellow', optionName: 'Color' },
{ Id: 3, Name: 'Blue', optionName: 'Color' },
{ Id: 4, Name: 'Green', optionName: 'Color' },
{ Id: 7, Name: 'Black', optionName: 'Color' },
{ Id: 8, Name: 'S', optionName: 'Size' },
{ Id: 11, Name: 'M', optionName: 'Size' },
{ Id: 12, Name: 'L', optionName: 'Size' },
{ Id: 13, Name: 'XL', optionName: 'Size' },
{ Id: 14, Name: 'XXL', optionName: 'Size' } ];
function groupBy(arr, key) {
var newArr = [],
types = {},
newItem, i, j, cur;
for (i = 0, j = arr.length; i < j; i++) {
cur = arr[i];
if (!(cur[key] in types)) {
types[cur[key]] = { type: cur[key], data: [] };
newArr.push(types[cur[key]]);
}
types[cur[key]].data.push(cur);
}
return newArr;
}
I use it like this. I just pass a function which defines how you want to group our data.
filterData= groupBy(Data,'optionName');
Result of this snippet of code output.....
[
{"type":"Color","data":[{"Id":1,"Name":"Red","optionName":"Color"},
{"Id":2,"Name":"Yellow","optionName":"Color"},
{"Id":3,"Name":"Blue","optionName":"Color"},
{"Id":4,"Name":"Green","optionName":"Color"},
{"Id":7,"Name":"Black","optionName":"Color"}]},
{"type":"Size","data":[{"Id":8,"Name":"S","optionName":"Size"},
{"Id":11,"Name":"M","optionName":"Size"},
{"Id":12,"Name":"L","optionName":"Size"},
{"Id":13,"Name":"XL","optionName":"Size"},
{"Id":14,"Name":"XXL","optionName":"Size"}]}
]
Show on fiddle
var originalList = [ { Id: 1, Name: 'Red', optionName: 'Color' },
{ Id: 2, Name: 'Yellow', optionName: 'Color' },
{ Id: 3, Name: 'Blue', optionName: 'Color' },
{ Id: 4, Name: 'Green', optionName: 'Color' },
{ Id: 7, Name: 'Black', optionName: 'Color' },
{ Id: 8, Name: 'S', optionName: 'Size' },
{ Id: 11, Name: 'M', optionName: 'Size' },
{ Id: 12, Name: 'L', optionName: 'Size' },
{ Id: 13, Name: 'XL', optionName: 'Size' },
{ Id: 14, Name: 'XXL', optionName: 'Size' } ];
var output = [{ Name: "Color", Data: [] },{ Name: "Size", Data: [] }] ;
originalList.map(function(entry){
if ( entry.optionName === "Color") output[0].Data.push({ Id: entry.Id, Name: entry.Name });
if ( entry.optionName === "Size") output[1].Data.push({ Id: entry.Id, Name: entry.Name });
});
'use strict'
let l = [ { Id: 1, Name: 'Red', optionName: 'Color' },
{ Id: 2, Name: 'Yellow', optionName: 'Color' },
{ Id: 3, Name: 'Blue', optionName: 'Color' },
{ Id: 4, Name: 'Green', optionName: 'Color' },
{ Id: 7, Name: 'Black', optionName: 'Color' },
{ Id: 8, Name: 'S', optionName: 'Size' },
{ Id: 11, Name: 'M', optionName: 'Size' },
{ Id: 12, Name: 'L', optionName: 'Size' },
{ Id: 13, Name: 'XL', optionName: 'Size' },
{ Id: 14, Name: 'XXL', optionName: 'Size' } ];
let color = [];
let size = [];
l.forEach(element => {
if (element['optionName'] === 'Color') {
color.push({'Id': element.Id, 'Name': element.Name});
} else {
size.push({'Id': element.Id, 'Name': element.Name});
}
});
console.log(color);
console.log(size);
You can try this method.
All of the answers lead to the same result, so it all comes down to a personal preference (or company guidelines) on how to tackle this.
// ES5 (traditional javascript) version
function groupByOptionName(list, optionName) {
return list
// filter out any item whose optionName does not match the desired name
.filter(function(item) {
return item.optionName === optionName;
})
// map the item into the desired shape
// (appears to be everything except optionName itself
.map(function(item) {
return {
Id: item.Id,
Name: item.Name
};
})
}
// ES2015/ES6 version
function groupByOptionName(list, optionName) {
return list
// filter out any item whose optionName does not match the desired name
.filter(item => item.optionName === optionName)
// map the item into the desired shape
// (appears to be everything except optionName itself
.map(item => {
Id: item.Id,
Name: item.Name
});
}
This function would let you program the desired result as follows:
var output = [
{Name: 'Color', Data: groupByOptionName(list, 'Color')},
{Name: 'Size', Data: groupByOptionName(list, 'Size')},
];
// the ES2015/ES6 version of this code would replace var with let
While the code itself differs, it is much like the other answers, with only a variation on the steps needed.
One could also opt to leave out any hardcoded option names (Color and Size) by extracting those aswel, this would allow for a more dynamic input, but could also introduce more processing that actually needed.
// ES5 (traditional javascript) version
function getOptionNames(list) {
return list
// map the array into a list of optionNames
.map(function(item) {
return item.optionName;
})
// remove duplicates
.filter(function(item, index, all) {
return all.indexOf(item) === index;
});
}
// ES2015/ES6 version (does exactly the same as the one above)
function getOptionNames(list) {
return list
// map the array into a list of optionNames
.map(item => item.optionName)
// remove duplicates
.filter((item, index, all) => all.indexOf(item) === index);
}
Which allows the result to be fully based on the input data:
// ES5 (traditional javascript) version
var output = getOptionNames(list)
// map the names into the desired structure
.map(function(buffer, name) {
return {
Name: name,
Data: groupByOptionName(list, name)
};
});
// ES2015/ES6 version (does exactly the same as the one above)
var output = getOptionNames(list)
// map the names into the desired structure
.map((buffer, name) => {
Name: name,
Data: groupByOptionName(list, name)
});
By writing all of the data-mangling steps in short consice steps you'd do yourself (especially your future self) a favor if this code ever needs to be adjusted.
If the data set really is heavy (in terms of a lot of data), you must also make sure to keep the number of copies you keep in memory limited. For example, if you never need the original dataset, make sure it can be garbage collected (by not having a variable containing it outside the scope where you receive the data)
Usage:
groupValues([
{ color: 'blue', value: 100 },
{ color: 'blue', value: 75 },
{ color: 'yellow', value: 50 },
{ color: 'yellow', value: 25 }
], 'color')
Result:
[
[{ color: 'blue', value: 100 }, { color: 'blue', value: 75 }],
[{ color: 'yellow', value: 50 }, { color: 'yellow', value: 25 }]
]
Function:
const groupValues = function(arr, key) {
const mapped = {}
arr.forEach(el => {
const actualKey = el[key]
if(!mapped.hasOwnProperty(actualKey)) mapped[actualKey] = []
mapped[actualKey].push(el)
})
return Object.keys(mapped).map(el => mapped[el])
}
The goal here is to group JSON data by date and convert it into object in Flutter.
API of service I'm using returns JSON in this format:
{
"id": 1,
"name": "Article Name",
"created_at": "2020-01-10T00:33:09.000000Z",
},
{
"id": 2,
"name": "Article Name",
"created_at": "2020-01-10T00:33:09.000000Z",
},
I need to convert it to following format:
Map<String, List<Article>> ArticleHistory = {
'04.08.2020': [
Article(id: 16, name: 'Article Name'),
Article(id: 15, name: 'Article Name'),
Article(id: 14, name: 'Article Name'),
Article(id: 13, name: 'Article Name'),
],
'03.08.2020': [
Article(id: 12, name: 'Article Name'),
Article(id: 11, name: 'Article Name'),
Article(id: 10, name: 'Article Name'),
Article(id: 9, name: 'Article Name'),
],
'02.08.2020': [
Article(id: 8, name: 'Article Name'),
Article(id: 7, name: 'Article Name'),
Article(id: 6, name: 'Article Name'),
Article(id: 5, name: 'Article Name'),
],
'01.08.2020': [
Article(id: 4, name: 'Article Name'),
Article(id: 3, name: 'Article Name'),
Article(id: 2, name: 'Article Name'),
Article(id: 1, name: 'Article Name'),
],
};
How that can be achieved?
Let you have data in the following format:
List<Map<String, dynamic>> articlesListJson = [
{
"id": 1,
"name": "Article 1",
"created_at": "2020-08-01T00:30:00.000000Z",
},
{
"id": 2,
"name": "Article 2",
"created_at": "2020-08-01T00:45:00.000000Z",
},
{
"id": 3,
"name": "Article 3",
"created_at": "2020-08-02T00:00:00.000000Z",
},
];
(If you have a json string instead, use jsonDecode function to parse it to Dart's List of Map's).
As you want to store dates as dd.mm.yyyy String, write a helper function for converting 2020-08-01T00:30:00.000000Z to 01.08.2020:
String extractDateString(String dateTimeString) {
DateTime dateTime = DateTime.parse(dateTimeString);
String day = dateTime.day.toString().padLeft(2, '0');
String month = dateTime.month.toString().padLeft(2, '0');
String year = dateTime.year.toString().padLeft(4, '0');
return '$day.$month.$year';
}
Then you'll be able to group the list by date:
Map<String, List<Map<String, dynamic>>> articleGroupsJson = groupBy(
articlesListJson,
(a) => extractDateString(a['created_at']),
);
// {'01.08.2020': [{...}, {...}], '02.08.2020': [{...}]}
groupBy is from collection package. Depend on it or just copy-paste function source.
Now parse each Map<String, dynamic> to Article class:
class Article {
int id;
String name;
Article({this.id, this.name});
}
in a standard way:
Article parseArticle(Map<String, dynamic> map) {
return Article(
id: map['id'],
name: map['name'],
);
}
Because the data is already groupped, instead of simply mapping the list you'll need to map groups, and for each group map its value (which is list)
Map<String, List<Article>> articleGroups = articleGroupsJson.map(
(date, list) => MapEntry(
date,
list.map(parseArticle).toList(),
),
);
Now articleGroups has the structure you want
I am quite new to react and want to feed my json response which i got from an api into an empty ant-design table and I am getting no clue on how to do that?
i have already mapped id with name but also want all other columns and into the table format of ant design.
JSon response
[
{
"id": 9685,
"name": "Mukesh Rai",
"count of sub": 3,
"count of int": 2,
"count of po": null
},
{
"id": 2085,
"name": "Abhyudaya Singh Panwar",
"count of sub": 1049,
"count of int": 17,
"count of po": 5
},
{
"id": 7087,
"name": "Amit Kumar Sharma",
"count of sub": 363,
"count of int": 68,
"count of po": 10
},
{
"id": 2100,
"name": "Aditya Kumar",
"count of sub": 724,
"count of int": 5,
"count of po": 1
}
]
component file
componentDidMount(){
axios.get("http://127.0.0.1:8000/marketer_details/")
.then(response=>{
console.log(response)
this.setState({posts: response.data})
})
.catch(error=> {
console.log(error)
})
}
render() {
const { posts } = this.state
return(
<div>
List of Posts
{
posts.length ?
posts.map(post => <div key = {post.id}>{post.name}</div>) :
null
}
</div>
)
//Wanted all other columns as well
render(){
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
width: '30%',
...this.getColumnSearchProps('name'),
},
{
title: 'Count of Submissions',
dataIndex: 'Count',
key: 'sub',
width: '20%',
...this.getColumnSearchProps('sub'),
},
{
title: 'Count of Interviews',
dataIndex: 'Count',
key: 'int',
...this.getColumnSearchProps('int'),
},
{
title: 'Count of PO',
dataIndex: 'Count',
key: 'po',
...this.getColumnSearchProps('po'),
},
];
return <Table columns={columns} dataSource={this.state.posts} />;
}
}
}
export default App
I am unable to understand how the multiple mapping could be done against each column row.
The Table component takes a column structure as argument.
Here, dataIndex refers to the index in the data that is to be referenced for the column, key is intended to remain unique across column names.
In your case, the columns array could be:
const columns = [
{
name: "Name",
dataIndex: "name"
},
{
name: "Count of submissions",
dataIndex: "count of sub"
},
{
name: "Count of interviews",
dataIndex: "count of int"
},
{
name: "Count of PO",
dataIndex: "count of po"
}
];
Codesandbox Demo
I need to set up a CheckboxGroup checkboxes with values loaded with json from some url.
What is a correct format of JSON?
Many thanks for help!
Update: I'll clarify my problem.
I'm using EditorGridPanel. Rows are Periods. There are columns Start_at, Finish_at, Region. First and second are date and everything ok with them. Problem with Region which actually is a CheckboxGroup with a checkbox for each week day - Monday, Tuesday, etc. So:
First I'm loading data from server into store
function setupDataSource() {
row = Ext.data.Record.create([
{ name: 'start_at', type: 'string' },
{ name: 'finish_at', type: 'string' },
{ name: 'region', type: 'string' }
]);
store = new Ext.data.Store({
url: '/country/195/periods',
reader: new Ext.data.JsonReader(
{
root: 'rows',
id: 'id'
},
row
)
});
store.load();
}
URL url: '/country/195/periods' returns JSON:
{"rows": [{"region": {"cbvert_1": 1, "cbvert_2": 0, "cbvert_3": 1, "cbvert_4": 0, "cbvert_5": 1, "cbvert_6": 0, "cbvert_7": 1}, "start_at": "2010-10-17", "id": 1, "finish_at": "2010-10-28"}]}
Then I'm building a grid:
function buildGrid() {
sm = new Ext.grid.RowSelectionModel();
cm = new Ext.grid.ColumnModel([
// ... Start at and Finish at columns definition here ...
{ header: 'Region',
dataIndex: 'region',
width: 150,
editor: new Ext.form.CheckboxGroup({
xtype: 'checkboxgroup',
columns: 7,
vertical: true,
items: [
{boxLabel: 'M', name: 'cbvert_1', inputValue: 1},
{boxLabel: 'T', name: 'cbvert_2', inputValue: 1},
{boxLabel: 'W', name: 'cbvert_3', inputValue: 1},
{boxLabel: 'T', name: 'cbvert_4', inputValue: 1},
{boxLabel: 'F', name: 'cbvert_5', inputValue: 1},
{boxLabel: 'S', name: 'cbvert_6', inputValue: 1},
{boxLabel: 'S', name: 'cbvert_7', inputValue: 1},
]
}),
renderer: function(value) {}
}]);
// ...
}
So, when I'm clicking on a grid cell I need to get checkboxes preselected with values previously stored in database. Now all checkboxes are stay blank but should be 1010101 as its in JSON.
Please point me to errors or maybe a some kind of a solution. Any help will be greatly appreciated.
Many thanks!
Check this out:
http://www.sencha.com/forum/showthread.php?47243-Load-data-in-checkboxgroup
Updated:
Remove the type declaration of the region field. You do not need a string but an object (from JSON). It works just fine that way :)