首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用node.js从redis获取等级数据

用node.js从redis获取等级数据
EN

Stack Overflow用户
提问于 2013-09-16 11:14:28
回答 2查看 3K关注 0票数 1

我希望外面的人能用这个来救我。由于某些原因,我无法思考node.js中的递归问题。如果有其他方法的话,它甚至不必是递归的。

我使用redis集将层次结构存储在集合中:

代码语言:javascript
复制
SADD parents.<name> <parent1> <parent2>

然后,parent1和parent2也会有条目,并且向上。我想把它转换成一个JSON对象数组。

JSON将如下所示:

代码语言:javascript
复制
[
 {
     label: <name>,
     parents: [
         { label: <parent1>,
           parents: [ {label: <grandparent1>}] },
         { label: <parent2> }
     ]
 }
]

以此类推。这应该可以工作在任何深度,虽然它平均将只有4-6个节点深。

下面是一些我一直在使用的代码,它使我达到了第一个层次:

代码语言:javascript
复制
var redis = require('node-redis');
var r_client = redis.createClient();

function get_parents (name, current, cb) {

        var output = new Array;
        output.push( { label: name, parents: [] } );

        r_client.smembers('parents.' + name, function(err, reply) {
            for (var i = 0; i < reply.length; i++)
            {
                var name = reply[i].toString('utf8');
                output[i].parents.push({label: name, parents: [] });
             }
             cb (output);
        });
}

get_parents( 'bob', function(out) {console.log('Final output: ' + JSON.stringify( out ))} );

我基本上想这么做:

  • 从根节点开始。打电话给瑞迪斯去找父母。
  • 为根节点构建对象。
  • 调用相同的函数来构建其他对象。
  • 当对redis的调用开始返回null时,调用将返回并开始组合对象。

任何帮助都将不胜感激。

编辑:更新的get_parents (仍然不能工作):

代码语言:javascript
复制
function get_parents (name, cb) {
    r_client.smembers('parents.' + name, function(err, reply) {
    for (var i = 0; i < reply.length; i++)
    {
      var name = reply[i].toString('utf8');
      output.push( { label: name, parents: [] } );
      output[i].parents = get_parents (output[i].parents.name, cb);
    }

    cb (output);
  });
}

编辑:我决定使用承诺,所以I pursued that option。谢谢你的帮助!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-09-17 16:09:09

TL;DR:我制作了一个NodeJS模块(RedisTree)和一个解释实现的blog post

上面的代码是最初的实现

不错的挑战!下面是一个与您的需求相匹配的实现,我添加了一个".save(tree,f)“方法,它使用了lodashasync,当然还有node

代码语言:javascript
复制
var sampleTree = [{
  label: 'label1',
  parents: [{
    label: 'label2',
    parents: [{
      label: 'label4',
      parents: []
    }]
  }, {
    label: 'label3',
    parents: []
  }]
}];

// Note: it's required to use a set in order to retrieve data
// SET:
// sadd label1 label2 label3
// sadd label2 label4
var _     = require('lodash');
var async = require('async');
var redis = require('redis').createClient();


function RedisTree(){}

/**
 * Iteratively & asynchronously retrieve an item from Redis
 * @param  {String} label label name (set name)
 * @param  {Function} f(err, arrayOfItems)
 */
RedisTree.prototype._getItem = function(label, f) {
  var parent = _.isArray(_.last(arguments)) ? _.last(arguments) : [];

  this.members(label, function(err, cards){
    var item = {
      label: this.label(label),
      parents: []
    };
    parent.push(item);

    if(cards.length === 0){return f(null, parent);}

    async.map(cards, _.partialRight(this._getItem.bind(this), item.parents), function(e){f(e, parent);});
  }.bind(this));
};

RedisTree.prototype._saveItem = function(item, f) {
  var labels = _.pluck(item.parents, 'label');
  if(labels.length === 0){return f();}

  redis.sadd(item.label, labels, function(err){
    if(err){return f(err);}
    this._saveItems(item.parents, f);
  }.bind(this));
};

/**
 *
 * @param  {Array} arrToSave array of items
 * @param  {Function} f(err)
 */
RedisTree.prototype._saveItems = function(arrToSave, f) {
  async.forEach(arrToSave, this._saveItem.bind(this), f);
};

/**
 * Retrieve a name from the label
 * Can be overridden to provide namespace support
 * e.g. return label.substring(2);
 * @return {[type]} [description]
 */
RedisTree.prototype.label = function(label){return label;};

/**
 * Retrieve every members of the `label` set from redis
 * Can be overridden to provide namespace support
 * e.g. redis.smembers('ns.'+label, f);
 * @param {[type]} label [description]
 * @param {[type]} f     [description]
 */
RedisTree.prototype.members = function(label, f) {redis.smembers(label, f);};

/**
 * Load a tree from Redis
 * @param  {String} startLabel Were to start
 * @param  {Function} f(err, tree)
 */
RedisTree.prototype.load = function(startLabel, f){this._getItem(startLabel, f);};

/**
 * Save a tree from Redis
 * @param  {Array} treeArray
 * @param  {Function} f(err, tree)
 */
RedisTree.prototype.save = function(treeArray, f){this._saveItems(treeArray, f);};

下面是如何使用它:

代码语言:javascript
复制
var t = new RedisTree();

// Save the sampleTree
t.save(sampleTree, function(err){
  // or ... retrieve it starting at "label1"
  t.load('label1', function(err, tree){
    console.log("sampleTree === ", JSON.stringify(tree, null, 1));
  });
});
票数 6
EN

Stack Overflow用户

发布于 2013-09-17 17:42:45

您确定不能将它作为JSON存储在磁盘上或使用MongoDB吗?另外,为什么你想要的结果是父母而不是孩子呢?

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18826583

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档