遍历节点/玉器中的相似键

时间:2018-07-29 16:07:01

标签: arrays node.js mongodb mongoose pug

我有一个从mongo数据库返回的猫鼬模型对象数组(使用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'}
]

类型未知,值未知。

我要为每种类型创建下拉列表,并填充该类型的值:

<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>

当前,我正在使用type作为数组键将对象数组转换为多维数组:

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

这似乎可行,但是在Jade中使用时,它会跳过facets对象,就好像它没有成员一样(尽管正在填充facets对象):

each fac, index in facets
select(name='#{index}', id='#{index}')
    each f in fac
        option(value='#{f._id}') #{f.name}

在遍历数组时是否做错了什么?

或者,有一种方法可以将数组直接从DB转换为类似这样的对象:

{
    type: 'colour',
    vals: {
        'red',
        'green',
        'blue'
    }
},
{
    type: 'material',
    vals: {
        'steel',
        'wood',
        'plastic'
    }

}

通话总量

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

这给了我输出:

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: , …}

2 个答案:

答案 0 :(得分:1)

您可以在$group下面尝试进行$push聚合

首先,您需要$grouptype字段,然后是$push,它返回一个值数组,这些值是通过将表达式应用于$group中的每个文档而得出的

Facet.aggregate([
  {
    "$group": {
      "_id": "$type",
      "vals": {
        "$push": "$value"
      }
    }
  },
  {
    "$project": {
      "vals": 1,
      "type": "$_id",
      "_id": false
    }
  }
]).then((result) => {
   console.log(result)
})

输出

[
  {
    "color": "material",
    "vals": [
      "steel",
      "wood",
      "plastic"
    ]
  },
  {
    "color": "colour",
    "vals": [
      "red",
      "blue",
      "green"
    ]
  }
]

答案 1 :(得分:1)

您可以像这样将所需的数据结构转换为所需的数据结构:

let data = [
    {_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'}
]

// build a temp object whose keys are the types
// and the data is an array of values for that type
let temp = new Map();
for (let item of data) {
    let type = item.type;
    let array = temp.get(type);
    if (!array) {
       array = [];
       temp.set(type, array);
    }
    array.push(item.value);
}

// convert that to your final requested format, an array of objects
let results = [];
for (let [type, vals] of temp) {
    results.push({type, vals});
}
console.log(results);