Adam P.
Adam P.

Reputation: 75

Update an object in a collection using Spring and Spring Data

I am attempting to save a single POJO into a MongoDB collection, and then update that same object. It is called a "Discovery" object, and it has the following set of fields:

private String displayName;
private String description;
private String contact;
private String defaultApiRoot;
private List<String> apiRoots;

I want "displayName" to be unique, so I am creating an index like so:

mongoOperations.indexOps(Discovery.class)
    .ensureIndex(new Index().on("displayName", Sort.Direction.ASC));

The index is created, as validated by:

> db.discovery.getIndexes()
[
  {
    "v" : 2,
    "key" : {
      "_id" : 1
    },
    "name" : "_id_",
    "ns" : "apiroot.discovery"
  },
  {
    "v" : 2,
    "key" : {
      "displayName" : 1
    },
    "name" : "displayName_1",
    "ns" : "apiroot.discovery"
  }
]

Perhaps I am misunderstanding indexes and Mongo, or Spring Data, but from every SO question and piece of documentation I have been able to find, performing a .save() with a Discovery Object that has a duplicate displayName, should result in an upsert on the fields for that object.

I am trying to update the object as follows:

Discovery discovery = discoveryRepository.findByDisplayName(displayName);
if (discovery.getApiRoots() == null || discovery.getApiRoots().isEmpty()) {
    discovery.setApiRoots(apiRoots);
} else {
    discovery.getApiRoots().addAll(apiRoots);
}
discoveryRepository.save(discovery);

This results in two objects:

> db.discovery.find()
{
    "_id" : ObjectId("5a16ee397e7a1b3789c970a7"),
    "_class" : "....Discovery",
    "displayName" : "X",
    "description" : "Default Discovery Description",
    "contact" : "[email protected]",
    "defaultApiRoot" : "Default API Root Display Name"
}
{
    "_id" : ObjectId("5a16ee3f7e7a1b3789c970a8"),
    "_class" : "....Discovery",
    "displayName" : "X",
    "description" : "Default Discovery Description",
    "contact" : "[email protected]",
    "defaultApiRoot" : "Default API Root Display Name",
    "apiRoots" : [
        "https://localhost:8001/Default+API+Root+Display+Name"
    ]
}

And when I try to "get" the object with discoveryRepository.findByDisplayName(displayName), I get:

{
    "display_name": "FLARE",
    "description": "Default Discovery Description",
    "contact": "[email protected]",
    "default": "Default API Root Display Name"
}

I am sure I am just completely missing the mark on how Mongo works here, but I would really appreciate if someone could help elucidate this. Bonus points if I can make a single DB call to update the object. I know the object's indexed key, so I don't really need to make the .find() call, but I can't get it to work in either case.

TL;DR: Using Spring and MongoDB, how do I update a subset of fields for an object stored in a collection, based on an indexed key other than _id?

Upvotes: 0

Views: 549

Answers (2)

Adam P.
Adam P.

Reputation: 75

What @pvpkiran said is correct for that question. For the main question, I used the following code to update a particular ApiRoot based on title:

    Query query = new Query(new Criteria("title").is(apiRoot.getTitle()));
    Update update = new Update();
    update.set("description", apiRoot.getDescription());
    update.set("versions", apiRoot.getVersions());
    update.set("maxContentLength", apiRoot.getMaxContentLength());
    mongoOperations.upsert(query, update, apiRootCollection);

Upvotes: 1

pvpkiran
pvpkiran

Reputation: 27078

With this statement

mongoOperations.indexOps(Discovery.class)
    .ensureIndex(new Index().on("displayName", Sort.Direction.ASC));  

You are just creating a index, which will make your searches faster, but doesn't say you want it to be unique

Do this

mongoOperations.indexOps(Discovery.class)
        .ensureIndex(new Index().on("displayName", Sort.Direction.ASC).unique());  

Upvotes: 1

Related Questions