I have an array of mongoose model objects being returned from a mongo database (using Model.find()
):
[
{_id: '...', type: 'colour', value: 'red'},
{_id: '...', type: 'colour', value: 'blue'},
{_id: '...', type: 'material', value: 'steel'},
{_id: '...', type: 'colour', value: 'green'},
{_id: '...', type: 'material', value: 'wood'},
{_id: '...', type: 'material', value: 'plastic'}
]
There is an unknown number of types with an unknown number of values.
I was to create drop downs for each type, populated with values of that type:
<select id="colour" name="colour">
<option value="abc123">red</option>
<option value="abc124">blue</option>
<option value="abc125">green</option>
</select>
<select id="material" name="material">
<option value="abc123">steel</option>
<option value="abc124">wood</option>
<option value="abc125">plastic</option>
</select>
Currently I am converting the array of objects to a multi dimensional array using the type
as the array key:
let facets = [];
for (var f in dbfacets) {
if (f != '0'){
if (dbfacets[f].type in facets) {
facets[dbfacets[f].type].push(dbfacets[f].name);
} else {
facets[dbfacets[f].type] = [];
facets[dbfacets[f].type].push(dbfacets[f].name);
}
}
}
This seems to work but when being used in Jade it skips the facets
object as if it has no members (despite the facets object being populated):
each fac, index in facets
select(name='#{index}', id='#{index}')
each f in fac
option(value='#{f._id}') #{f.name}
Is there something I'm doing wrong iterating over the array?
Alternatively is there a way to convert the array directly from the DB to an object like:
{
type: 'colour',
vals: {
'red',
'green',
'blue'
}
},
{
type: 'material',
vals: {
'steel',
'wood',
'plastic'
}
}
Calling aggregate
Facet.collection.aggregate([
{
'$group': {
'_id': '$type',
'vals': {
'$push': '$value'
}
}
},
{
'$project': {
'vals': 1,
'type': '$_id',
'_id': false
}
}
], (err, result) => {
if (err){return next(err);}
console.log(result);
});
This gives me an output of:
result
AggregationCursor {pool: null, server: null, disconnectHandler: Store, bson: BSON, ns: "toylib.facets", …}
_events:Object {}
_eventsCount:0
_maxListeners:undefined
_readableState:ReadableState {objectMode: true, highWaterMark: 16, buffer: BufferList, …}
bson:BSON {}
cmd:Object {aggregate: "facets", pipeline: Array(2), cursor: Object}
cursorState:Object {cursorId: null, cmd: Object, documents: Array(0), …}
destroyed:false
disconnectHandler:Store {s: Object, length: <accessor>}
domain:null
logger:Logger {className: "Cursor"}
ns:"toylib.facets"
options:Object {readPreference: null, cursor: Object, promiseLibrary: , …}
pool:null
readable:true
readableHighWaterMark:16
s:Object {maxTimeMS: null, state: 0, streamOptions: Object, …}
server:null
sortValue:undefined
topology:Server {domain: null, _events: Object, _eventsCount: 26, …}
__proto__:Readable {_next: , setCursorBatchSize: , cursorBatchSize: , …}
You can try below $group
with $push
aggregation
Firstly you need to $group
your type
field and then $push
which returns an array of values that result from applying an expression to each document in a $group
Facet.aggregate([
{
"$group": {
"_id": "$type",
"vals": {
"$push": "$value"
}
}
},
{
"$project": {
"vals": 1,
"type": "$_id",
"_id": false
}
}
]).then((result) => {
console.log(result)
})
Output
[
{
"color": "material",
"vals": [
"steel",
"wood",
"plastic"
]
},
{
"color": "colour",
"vals": [
"red",
"blue",
"green"
]
}
]