我试图遍历Firebase列表(使用AngularFire2),我希望得到一个Promise来指示嵌套循环何时完成,以便我可以处理第二个操作。我使用以下代码:
console.log('START');
this.af.database.list('Sites/123123/Users')
.map(users => {
users.map(user => {
console.log('found a user ', user);
this.af.database.list('registeredUsers/' + user.$key + '/Sites')
.forEach(sites => {
sites.forEach(site => {
if (site.$value == '123123') {
console.log('found site ', site.$key);
}
});
});
});
}).first().toPromise().then(function (x) {
console.log('ALL DONE')
});
输出结果为:
但是我只在外部循环之后获得Promise,而不是等待嵌套循环完成。有什么建议吗?
答案 0 :(得分:1)
你在地图调用中缺少return语句,因为你在用户可观察的第一个地图中生成了新的Observable,你应该在这里使用mergeMap:
console.log('START');
this.af.database
.list('Sites/123123/Users')
.mergeMap(users => {
return users.map(user => {
console.log('found a user ', user);
return this.af.database.list('registeredUsers/' + user.$key + '/Sites')
.forEach(sites => {
sites.forEach(site => {
if (site.$value == '123123') {
console.log('found site ', site.$key);
}
});
});
});
})
.first().toPromise().then(x => {
console.log('ALL DONE')
});
这里我有一个简化的代码版本,消除了对firebase应用程序的依赖:
//const Rx = require('rxjs'); // require Rx on nodejs instead of html script tag
const usersObservable = Rx.Observable.from([[{ id: 1, $key: 123 }]]);
const sitesObservable = Rx.Observable.from(
new Promise((resolve) => {
setTimeout(() => {
resolve([{ $value: '123123', $key: 'site1' }, { $value: '0', $key: 'site2' }])
}, 500);
})
);
console.log('START');
usersObservable
.mergeMap((users) => {
return users.map(user => {
console.log('found a user ', user);
return sitesObservable
.forEach(sites => {
sites.forEach(site => {
if (site.$value == '123123') {
console.log('found site ', site.$key);
}
});
});
});
})
.first().toPromise().then(x => {
console.log('ALL DONE')
});

<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.0.1/Rx.js"></script>
&#13;
以下是生成的输出:
START
found a user {
"id": 1,
"$key": 123
}
found site site1
ALL DONE
添加了特定的firebase代码后,您的代码应如下所示:
console.log('START');
var siteUsers = this.af.database.list('Sites/-KcF5J9SoSHDrUEYO-Ed/Users');
siteUsers
.mergeMap(users => {
console.log('users = ', users);
return users.map(user => {
console.log('found a user ', user);
return this.af.database.list('registeredUsers/' + user.$key + '/Sites')
.forEach(sites => {
console.log('sites = ', sites)
sites.forEach(site => {
if (site.$value == '-KcF5J9SoSHDrUEYO-Ed') {
console.log('found site ', site.$key);
}
});
});
});
})
.first().toPromise().then(x => {
console.log('ALL DONE')
});
答案 1 :(得分:1)
@Kalle
我也尝试过这种方式,同样如此:
console.log('START');
var siteUsers = this.af.database.list('Sites/-KcF5J9SoSHDrUEYO-Ed/Users');
const siteUsersObservable = Observable.from(siteUsers);
siteUsersObservable
.map(users => {
console.log('users = ', users);
return users.map(user => {
console.log('found a user ', user);
var userSites = this.af.database.list('registeredUsers/' + user.$key + '/Sites');
const userSitesObservable = Observable.from(userSites);
return userSitesObservable
.forEach(sites => {
console.log('sites = ', sites)
sites.forEach(site => {
if (site.$value == '-KcF5J9SoSHDrUEYO-Ed') {
console.log('found site ', site.$key);
}
});
});
});
})
.first().toPromise().then(x => {
console.log('ALL DONE')
});
并且firebase结构是这样的:
我的结果是: