如何动态更改文档结构,从标量值合并到数组中?

时间:2014-03-10 20:24:49

标签: java mongodb mongodb-java

我有一系列文件:

{"name":1,"b":3,"c":3}
{"name":1,"b":3,"c":5}
{"name":1,"b":3,"c":6}
{"name":2,"b":6,"c":6}
{"name":2,"b":6,"c":7}
{"name":2,"b":6,"c":3}
{"name":3,"b":2,"c":3}
{"name":4,"b":2,"c":3}

我想将该集合合并到以下结果中:

{"name":1,"b":3,"c":[3,5,6]}
{"name":2,"b":6,"c":[6,7,3]}
{"name":3,"b":2,"c":3}
{"name":4,"b":2,"c":3}

这意味着消除重复文档并将其c字段保存为数组。 c将是一个数组。

注意:第一个(例如"名称")和第二个(例如" b")字段对于每个文档都是唯一的。

while (cursor.hasNext()) {
       DBObject currentObject = cursor.next();
       String currentName = (String)currentObject.get("name");
        if (currentName.equals(previousName) && !previousName.equals(""))
        {
            // what should i write here 
            collection.remove(previousObject);
        }
        previousObject = currentObject;
        previousName = (String)previousObject.get("name");
    }

3 个答案:

答案 0 :(得分:1)

您可以在进度时将名称地图和DBObjects以及push保存到值中,如下所示:

    Map<String,DBObject> names = new HashMap<String, DBObject>();
    while (cursor.hasNext()) {
        DBObject currentObject = cursor.next();
        String currentName = (String) currentObject.get("name");
        DBObject o = names.get(currentName);
        if (o!=null) { //means you already have it.
            Integer c = (Integer) currentObject.get("c");
            collection.remove(currentObject);
            collection.update(o,new BasicDBObject("$push",new BasicDBObject("c",c)));
        }else {
            names.put(currentName,currentObject);
        }
    }

答案 1 :(得分:0)

我不了解MongoDB,但是因为naimdjon说你需要一些地图。 以下是针对您的问题的通用Java解决方案:

模拟输入的课程

import java.util.HashSet;
import java.util.Set;


public class SomeDbObject {
    Integer name;
    Integer b;
    Set<Integer> c;


    public SomeDbObject(Integer name, Integer b, Integer c){
        this.name = name;
        this.b = b;
        this.c = new HashSet<>();
        this.c.add(c);
    }

    public String toString(){
        return c.toString();
    }
}

现在是一个包含数据集的测试类(使用名称和b作为&#34;键&#34;):

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.junit.Test;


public class SomeDbObjectTest {

    @Test
    public void testProblem(){

        List<SomeDbObject> l = new ArrayList<SomeDbObject>();
        l.add(new SomeDbObject(1,3,3));
        l.add(new SomeDbObject(1,3,5));
        l.add(new SomeDbObject(1,3,6));
        l.add(new SomeDbObject(2,6,6));
        l.add(new SomeDbObject(2,6,7));
        l.add(new SomeDbObject(2,6,3));
        l.add(new SomeDbObject(3,2,3));
        l.add(new SomeDbObject(4,2,3));

        Map<Integer,Map<Integer,SomeDbObject>> m = new HashMap<Integer,Map<Integer,SomeDbObject>>();

        for(SomeDbObject tc : l){
            Map<Integer,SomeDbObject> mTc = m.get(tc.name);

            if(mTc == null){
                mTc = new HashMap<Integer,SomeDbObject>();
                mTc.put(tc.b, tc); 
                m.put(tc.name, mTc);
            } else {
                SomeDbObject alreadyExistingRec = mTc.get(tc.b);
                alreadyExistingRec.c.addAll(tc.c);
            }
        }

        System.out.println(m);
    }
}

答案 2 :(得分:0)

您可以使用聚合框架在shell中使用以下查询来执行此操作:

db.foo.aggregate([
{$group:{_id:{name:"$name", b:"$b"}, c:{$addToSet:"$c"}}}, 
{$project:{_id:0, name:"$_id.name", b:"$_id.b", c:1}}
])

此查询可以翻译为Java。