我正在开发MEANJS项目。这是一个通过递归获取数据返回数组的函数。现在,我遇到了如何获取该数组的问题。
问题: -
让用户 A 拥有{_id:' 001',rmUserId:' 001'}, B :{ _id:' 002',rmUserId:' 001'}, C {_id:' 003',rmUserId:' 002& #39;}, D {_ id:' 003',rmUserId:' 001'}, E {_id:&# 39; 004',rmUserId:' 009'}
如果用户 A 将登录,则allUnderUsers
阵列具有 B,C,D 用户。这意味着所有用户都必须遵循自己的层次结构。
A
/ \
B D
/
C
这是我的代码: -
module.exports.getUnderUsersByRm = function(currentUser, callback) {
try {
var allUnderUsers = [];
function __getUserByRmId(rmId) {
User.find({ rmUserId: rmId, isAlive: true, status: 'active' })
.exec(function(err, users) {
if (err)
return callback(err)
if (users.length > 0) {
users.forEach(function(ele, i) {
allUnderUsers.push(ele);
__getUserByRmId(ele.rmUserId);
});
} else {
return false;
}
})
}
__getUserByRmId(currentUser._id);
} catch (e) {
callback(e)
}
}
这里我需要在调用所有递归函数后得到 allUnderUsers 数组。
我使用了回调函数,如: -
....
...
__getUserByRmId(currentUser._id);
callback(null,'done');
.
.
但它会抛出一个错误,即
错误:发送后无法设置标头
.at ServerResponse.OutgoingMessage.setHeader(_http_outgoing.js:346:11) 在ServerResponse.header(/home/clsah/projects/LMS/node_modules/express/lib/response.js:719:10) ........ .......
答案 0 :(得分:2)
如果您利用mongoose更高版本中内置的promise并在模块中显示promise接口,则可以执行以下操作:
此处模拟运行代码:https://jsfiddle.net/jfriend00/zr6ynmsu/
<Grid
Background="Azure"
BorderBrush="Pink"
BorderThickness="2">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="col1" Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
x:Name="txt1"
Foreground="Blue"
Text="layouttest1layouttest1layouttest1layou"
TextWrapping="Wrap" />
<TextBlock
Grid.Column="1"
Foreground="Red"
x:Name="txt2"
Text="layouttest2layouttest2layouttest2layouttest2layout"
TextWrapping="Wrap" />
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger x:Name="adptivetrigger" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="col1.Width" Value="Auto" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
然后,你会像这样使用它:
private void Page_Loaded(object sender, RoutedEventArgs e)
{
var testwidth = txt1.ActualWidth + txt2.ActualWidth;
adptivetrigger.MinWindowWidth = testwidth;
}
如果你仍然想在getUnderUsersByRm上使用你的回调接口,你仍然可以这样做(尽管如果你做的不仅仅是一些异步调用,那么真的值得使用所有异步操作的promises):
module.exports.getUnderUsersByRm = function(currentUser) {
function __getUserByRmId(rmId) {
// return promise here
return User.find({ rmUserId: rmId, isAlive: true, status: 'active' }).exec().then(function(users) {
if (users.length > 0) {
let promises = [];
users.forEach(function(ele, i) {
promises.push(__getUserByRmId(ele.rmUserId));
});
// return promise which will chain it to original promise
// this is the key to getting the master promise to wait
// for everything to be done
return Promise.all(promises).then(results => {
// add in previous results
// flatten all the results together into a single array
// and remove empty results
results.unshift(users);
return [].concat.apply([], results.filter(item => item.length > 0));
});
} else {
return [];
}
});
}
return __getUserByRmId(currentUser);
}
如果您的用户树是循环的,那么您可以通过跟踪所有访问过的用户来防止无限循环。您需要某种识别每个用户的唯一密钥。由于我不知道你的程序中有什么,我将假设你传入的用户已经是id。唯一标识用户的任何属性都将在此方案中起作用:
const someModule = require('yourModule');
someModule.getUnderUsersByRm(someUser).then(results => {
// process all results here
}).catch(err => {
// error here
});
答案 1 :(得分:1)
async.until
并维护要处理的元素数组var async = require('async');
module.exports.getUnderUsersByRm = function(currentUser, callback) {
try {
var allUnderUsers = [];
var usersToProcess = [currentUser._id]; // Array to track what was earlier done with recursion
async.until(function() { // Test function for async.until
return usersToProcess.length === 0;
}, function __getUserByRmId(callback2) { // fn for async.until
User.find({
rmUserId: usersToProcess.shift(), // Take first element of array
isAlive: true,
status: 'active'
})
.exec(function(err, users) {
if (err)
return callback2(err)
if (users.length > 0) {
users.forEach(function(ele, i) {
allUnderUsers.push(ele);
usersToProcess.push(ele.rmUserId);
// __getUserByRmId(ele.rmUserId); // To Remove
});
return callback2(); // Always call callback;
} else {
return callback2(); // Earlier: return false; Return some err argument if you want
}
})
}, callback); // Final callback for async.until
} catch (e) {
callback(e);
}
}
答案 2 :(得分:1)
我尝试使用基于async
的方法实施解决方案。你可能觉得它很天真,但它应该有用。
function __getUserByRmId(rmId, cb) {
var allUnderUsers = [];
User.find({ rmUserId: rmId, isAlive: true, status: 'active' })
.exec(function(err, users) {
async.each(users, function(user, callback){
if (user._id != rmId){
// recursive call
__getUserByRmId(user._id, function(childUsers){
childUsers.forEach(function (childUser) {
allUnderUsers.push(childUser);
});
callback(); //intermediate callback for async call
});
} else { //condition check to avoid infinite loop
allUnderUsers.push(user);
callback(); //intermediate callback for-loop
}
}, function(err){
cb(allUnderUsers); //final callback with result
});
});
}
module.exports.getUnderUsersByRm = function(currentUser, callback) {
__getUserByRmId(currentUser._id, callback)
};
从逻辑上讲,它应该有效。如果有任何问题,请试试让我知道。现在,它也返回包含父元素的数组。例如[A,B,C,D]为您的例子。
答案 3 :(得分:0)
我很确定你收到了这个错误,因为你运行__getUserByRmId
函数(如果发生错误,里面会调用callback
函数,然后,除了发生的任何事情,你调用{ {1}}再次运行,可能会向同一个请求发送多个响应,依此类推,即使已经发送了响应,也会多次设置标头。
我应该在评论中发帖,但没有足够的声誉这样做