Java MongoDB:更新对象数组中的一个项目

时间:2015-11-01 10:30:15

标签: java arrays mongodb

让我说我有这个对象:

{
"_class" : "com.foo.Person",
"_id" : "2894",
"name" : "Pixel Spacebag",
"photos" : [
    {
        "_id" : 10,
         "amount" : "100"
    },
    {
        "_id" : 11,
         "amount" : "200"
    }
    ]
}

现在,我想在照片对象的“照片”数组中添加一个额外的字段。

我想在照片_id = 10中添加“发行商”字段:“Pixel Studios”。

        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(new ObjectId("2984"));
        Update update = new Update();
        update.set("distributor", "Pixel Studios");
        mongoTemplate.updateFirst(query, update, Person.class);

我可以正确访问Person对象,但我无法正确更新specfic photo _id 10。

有谁知道如何正确更新?

2 个答案:

答案 0 :(得分:1)

我挖了一会儿,实际上找到了解决方案。它以位置运算符的形式出现:

https://docs.mongodb.org/manual/reference/operator/projection/positional/

我还阅读了与位置运算符相关的这个线程,以及如何更新数组的元素:

How to update value of specific embedded document, inside an array, of a specific document in MongoDB?

com.mongodb.DBCollection collection = mongoTemplate.getDb().getCollection("person");
            ObjectId _id = new ObjectId("2984");
            ObjectId photos_id = new ObjectId(10);

            BasicDBObject query = new BasicDBObject();
            query.put("_id", _id);
            query.put("photos._id", photos_id);

            BasicDBObject data = new BasicDBObject();
            data.put("photos.$.distributor", "Pixel Studios");

            BasicDBObject command = new BasicDBObject();
            command.put("$set", data);

            collection.update(query, command);

答案 1 :(得分:0)

在客户端修改从数据库中获取的对象要容易得多 我在这里假设photos内的文档是由_id排序的,如果不是你必须在数组内搜索,那么还有一些步骤。 首先,这里是你如何在mongo shell(JavaScript)中执行此操作,但这在Java中应该没有太大的不同:

> v = db.ppl.find({_id: "2894"}).next();
{
    "_id" : "2894",
    "_class" : "com.foo.Person",
    "name" : "Pixel Spacebag",
    "photos" : [
        {
            "_id" : 10,
            "amount" : "100"
        },
        {
            "_id" : 11,
            "amount" : "200"
        }
    ]
}
> v.photos[0]
{ "_id" : 10, "amount" : "100" }
> v.photos[0].distributor = "pixel studios"
> v.photos[0]
{ "_id" : 10, "amount" : "100" }
> v.photos[0].distributor = "pixel studios"

> db.ppl.update({_id:"2894"}, {$set : {"photos": v.photos}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.ppl.findOne()
{
    "_id" : "2894",
    "_class" : "com.foo.Person",
    "name" : "Pixel Spacebag",
    "photos" : [
        {
            "_id" : 10,
            "amount" : "100",
            "distributor" : "pixel studios"
        },
        {
            "_id" : 11,
            "amount" : "200"
        }
    ]
}

因此,在我使用.进行分配的情况下,您必须使用适当的get或set方法,并为正确的类型进行可能的转换。

以下代码是我在上面发布的JS的Java等价物:

Document example = new Document("_class", "com.foo.Person")
                .append("_id", "2894")
                .append("name", "Pixel Spacebag");

        List<Document> photos = new ArrayList<Document>();
        photos.add(new Document("_id", 10).append("amount", "100"));
        photos.add(new Document("_id", 11).append("amount", "200"));

        example.append("photos", photos);
        collection.insertOne(example);

        FindIterable<Document> res = collection.find(new Document("_id", "2894"));
        Document temp = res.iterator().next();
        List<Document> photosDoc = (List<Document>) temp.get("photos");
        Document docToUpdate = photosDoc.get(0);
        docToUpdate.append("distributor", "pixel studios");
        photosDoc.set(0, docToUpdate);
        collection.updateOne(new Document("_id", temp.get("_id")),
                new Document("$set", new Document("photos", photosDoc)));

        /* Check that everything worked */
        res = collection.find(new Document("_id", "2894"));
        Document updatedDocument = res.iterator().next();
        System.out.println(updatedDocument);
        /* outputs:
         Document{{_id=2894, _class=com.foo.Person, name=Pixel Spacebag, photos=[Document{{_id=10, amount=100, distributor=pixel studios}}, Document{{_id=11, amount=200}}]}}
         */