Mapreduce将输入字符串拆分为输出数组

时间:2014-06-09 15:25:20

标签: arrays mongodb split mapreduce

我正在处理以下文件:

> db.productData.find({"upc" : "XXX"}).pretty()
{
    "_id" : ObjectId("538dfa3d44e19b2bcf590a77"),
    "upc" : "XXX",
    "productDescription" : "bla foo bar bla bla fooX barY",
    "productSize" : "",
    "ingredients" : "foo; bar; foo1; bar1.",
    "notes" : "bla bla bla"
}
> 
  • 我希望有一个文档,其中包含一个分割成分的列表/数组(在;上)。我想将原始集合的字符串拆分为字符串数组。
  • 我想只映射输出集合中的一些输入字段。
  • 我想在MongoDB上使用mapreduce

我尝试了很多不同的方法将资源从map函数转移到reduce函数无法找到合适的解决方案。 从我执行的所有尝试中,现在我知道我需要检查null值等,所以以下是我的最后一次尝试:

地图功能:

var mapperProductData = function () {

    var ingredientsSplitted = values.ingredientsString.split(';');

    var objToEmit = {barcode : "", description : "", ingredients : []};

    // checking for null (is this strictly necessary? why?)
    if ( 
            this.hasOwnProperty('ingredients')
         && this.hasOwnProperty('productDescription')
         && this.hasOwnProperty('upc')
       ) {
        for (var i = 0; i < ingredientsSplitted.length; i++) {
            // I want to emit a new document only when I have all the splitted strings inside the array
            if (i == ingredientsSplitted.length - 1) {
                 objToEmit.barcode     = this.upc;
                 objToEmit.description = this.productDescription;
                 objToEmit.ingredients = ingredientsSplitted;

                 emit(this.upc, objToEmit);
            }
        }
    }
};

减少功能:

    var reducerNewMongoCollection = function(key, values) {

    return values;
};

map-reduce调用:

db.productData.mapReduce(
    mapperProductData,
    reducerNewMongoCollection,
    {
        out : "newMongoCollection" ,
        query: { "values" : {$exists: true} }
    }
);

我在输出中得到一个空集合(newMongoCollection为空)。 我做错了什么?

1 个答案:

答案 0 :(得分:3)

让我们从头开始。您的地图功能应如下所示:

var mapperProductData = function () {    
    var ingredientsSplitted = this.ingredients.split(';');    
    var objToEmit = {
        barcode : this.upc, 
        description : this.productDescription, 
        ingredients : ingredientsSplitted
    };

    emit(this.upc, objToEmit);        
};

你的map-reduce调用应该是:

db.productData.mapReduce(
    mapperProductData,
    reducerNewMongoCollection,
    {
        out : "newMongoCollection", 
        query : { 
            upc : { $exists : true }, 
            productDescription : { $exists : true }, 
            ingredients : { $exists : true , $type : 4 }
        } 
    }
);

查询部分将过滤具有相关字段的文档。此外,查询参数$type将仅匹配成分为数组的文档。这样您就不需要在地图功能中进行复杂的检查,并且发送到map功能的文档数量会更少。

测试文档文档的结果如下所示:

key : XXX, 
value: {
    "barcode" : "XXX",
    "description" : "bla foo bar bla bla fooX barY",
    "ingredients" : [
        "foo",
        " bar",
        " foo1",
        " bar1."
    ]
}