【发布时间】:2019-02-06 00:40:42
【问题描述】:
我有一个数据库,它正在调用最近消息的列表。每条消息都是一个对象,并作为这些消息对象的数组存储在 chatListNew 中。
每个消息对象都有一个属性“from”,即发布它的用户的 ID。我想要做的是循环遍历这个数组并将“From”用户的实际配置文件信息附加到对象本身中。这样,当前端接收到信息时,它就可以在相应消息的 fromProfile 属性中访问一个特定消息的发件人配置文件。
我考虑过遍历每一个并为每一个执行 Promise.All,但是,如果只有少数几个用户发布了数百条消息,那将是非常昂贵的。 只为每个用户运行一次 mongoose 查询会更有意义。于是我发明了一个缓存系统。
但是,我对如何将未来值的承诺存储在数组元素中感到困惑。我认为将“fromProfile”设置为之前调用的承诺会神奇地保持这个承诺,直到值被解决。所以我使用 Promise.all 来确保所有的 Promise 都已完成,然后由结果返回,但是我存储在数组中的 Promise 并不是我希望的值。
这是我的代码:
//chatListNew = an array of objects, each object is a message that has a "from" property indicating the person-who-sent-the-message's user ID
let cacheProfilesPromises = []; // this will my basic array of the promises called in the upcoming foreach loop, made for Promise.all
let cacheProfilesKey = {}; // this will be a Key => Value pair, where the key is the message's "From" Id, and the value is the promise retrieving that profile
let cacheProfileIDs = []; // this another Key => Value pair, which basically stores to see if a certain "From" Id has already been called, so that we can not call another expensive mongoose query
chatListNew.forEach((message, index) => {
if(!cacheProfileIDs[message.from]) { // test to see if this user has already been iterated, if not
let thisSearch = User.findOne({_id : message.from}).select('name nickname phone avatar').exec().then(results => {return results}).catch(err => { console.log(err); return '???' ; }); // Profile retrieving promise
cacheProfilesKey[message.from] = thisSearch;
cacheProfilesPromises.push(thisSearch); // creating the Array of promises
cacheProfileIDs[message.from] = true;
}
chatListNew[index]["fromProfile"] = cacheProfilesKey[message.from]; // Attaching this promise (hoping it will become a value once promise is resolved) to the new property "fromProfile"
});
Promise.all(cacheProfilesPromises).then(_=>{ // Are all promises done?
console.log('Chat List New: ', chatListNew);
res.send(chatListNew);
});
这是我的控制台输出:
Chat List New: [ { _id: '5b76337ceccfa2bdb7ff35b5',
updatedAt: '2018-08-18T19:50:53.105Z',
createdAt: '2018-08-18T19:50:53.105Z',
from: '5b74c1691d21ce5d9a7ba755',
conversation: '5b761cf1eccfa2bdb7ff2b8a',
type: 'msg',
content: 'Hey everyone!',
fromProfile:
Promise { emitter: [EventEmitter], emitted: [Object], ended: true } },
{ _id: '5b78712deccfa2bdb7009d1d',
updatedAt: '2018-08-18T19:41:29.763Z',
createdAt: '2018-08-18T19:41:29.763Z',
from: '5b74c1691d21ce5d9a7ba755',
conversation: '5b761cf1eccfa2bdb7ff2b8a',
type: 'msg',
content: 'Yo!',
fromProfile:
Promise { emitter: [EventEmitter], emitted: [Object], ended: true } } ]
而我希望得到类似的东西:
Chat List New: [ { _id: '5b76337ceccfa2bdb7ff35b5',
updatedAt: '2018-08-18T19:50:53.105Z',
createdAt: '2018-08-18T19:50:53.105Z',
from: '5b74c1691d21ce5d9a7ba755',
conversation: '5b761cf1eccfa2bdb7ff2b8a',
type: 'msg',
content: 'Hey everyone!',
fromProfile:
Promise {name: xxx, nickname: abc... etc} },
{ _id: '5b78712deccfa2bdb7009d1d',
updatedAt: '2018-08-18T19:41:29.763Z',
createdAt: '2018-08-18T19:41:29.763Z',
from: '5b74c1691d21ce5d9a7ba755',
conversation: '5b761cf1eccfa2bdb7ff2b8a',
type: 'msg',
content: 'Yo!',
fromProfile:
{name: xxx, nickname: abc... etc} } ]
谢谢你们!开放其他方式来实现这一点:) 皮特
【问题讨论】:
-
这不是 Promise.all 的工作原理!
-
如果我是你,我不会将 fromProfile 合并到列表中的每个项目中。我会把它们分开,然后把工作交给客户。您的有效负载会小得多,如果需要,客户端甚至可以缓存 fromProfiles。你仍然可以通过实现所谓的“sideloading”使其成为一个请求。本质上,您的 json 将有两个根节点,“fromProfiles”是一个数组,“chatItems”是您现在拥有的数组。
标签: javascript node.js mongoose promise