I have a list of objects which I want to insert into a collection. The mongoTemplate.insert(list); works fine but now I want to modify it to upsert(); as my list can contain duplicate objects which are already inserted into a collection. So what I want is insert entire list and on the go check if the item is already present in the collection then skip it else insert it.
You can try out continueOnError or ordered flag like this:
db.collection.insert(myArray, {continueOnError: true})
OR,
db.collection.insert(myArray, {ordered: false})
You need to create a unique index field of your object's id(if there is no unique constraint). So that it will make error while you try to insert using same id.
Using the unique constraint you insert array or using BulkInsert
For using insert you can set a flag continueOnError: true which can continue insertion whenever error found in case of error because of unique constraint while inserting existing id of object.
The only way to do a bulk-upsert operation is the method MongoCollection.bulkWrite (or at least: the only way I know... ;-))
To use it, you have to convert your documents to the appropriate WriteModel: for upserts on a per-document basis, this is UpdateOneModel.
List<Document> toUpdate = ...;
MongoCollection coll = ...;
// Convert Document to UpdateOneModel<Document>
List<UpdateOneModel<Document>> bulkOperationList = toUpdate.stream()
.map(doc -> new UpdateOneModel<Document>(
Filters.eq("_id", doc.get("_id")), // identify by same _id
doc,
new UpdateOptions().upsert(true)))
.collect(Collectors.toList());
// Write to DB
coll.bulkWrite(bulkOperationList);
(Disclaimer: I only typed this code, I never ran it)
Related
Currently i am mapping from list of pojos to Record, and i want to be able to insert multiple rows at once. how can i do that in JOOQ with one transaction?
List<Record> recordList = receiverList.stream().map(r -> {
return dslContext.newRecord(Table, r);
}).collect(Collectors.toList());
I have tried put the list in the "values", but getting exception "The number of values must match the number of fields"
dslContext.insertInto(Table).values(recordList);
Your error is because .values(...) is waiting for field values not Record.
Maybe you can do a batch execution :
dslContext.batchInsert(recordList);
As Lukas mentioned it, it will execute it in a single jdbc statement which is atomic
instead of batchInsert you can also do:
var insertStepN = dslContext.insertInto(Table).set(dslContext.newRecord(Table, recordList.get(0));
for (var record : recordList.subList(1, recordList.size()) {
insertStepN = insertStepN.newRecord().set(dslContext.newRecord(Table, record));
}
insertStepN.returning().fetch().into(YourClass.class);
this way you can get the inserted values back using returning(), which you won't get with batchInsert().
I'm new to couchbase. I'm using Java for this. I'm trying to remove a document from a bucket by looking up its ID with query parameters(assuming the ID is unknown).
Lets say I have a bucket called test-data. In that bucked I have a document with ID of 555 and Content of {"name":"bob","num":"10"}
I want to be able to remove that document by querying using 'name' and 'num'.
So far I have this (hardcoded):
String statement = "SELECT META(`test-data`).id from `test-data` WHERE name = \"bob\" and num = \"10\"";
N1qlQuery query = N1qlQuery.simple(statement);
N1qlQueryResult result = bucket.query(query);
List<N1qlQueryRow> row = result.allRows();
N1qlQueryRow res1 = row.get(0);
System.out.println(res1);
//output: {"id":"555"}
So I'm getting a json that has the document's ID in it. What would be the best way to extract that ID so that I can then remove the queryed document from the bucket using its ID? Am I doing to many steps? Is there a better way to extract the document's ID?
bucket.remove(docID)
Ideally I'd like to use something like a N1q1QueryResult to get this going but I'm not sure how to set that up.
N1qlQueryResult result = bucket.query(select("META.id").fromCurrentBucket().where((x("num").eq("\""+num+"\"")).and(x("name").eq("\""+name+"\""))));
But that isn't working at the moment.
Any help or direction would be appreciated. Thanks.
There might be a better way which is running this kind of query:
delete from `test-data` use keys '00000874a09e749ab6f199c0622c5cb0' returning raw META(`test-data`).id
or if your fields has index:
delete from `test-data` where name='bob' and num='10' returning raw META(`test-data`).id
This query deletes the specified document with given document key (which is meta.id) and returns document id of deleted document if it deletes any document. Returns empty if no documents deleted.
You can implement this query with couchbase sdk as follows:
Statement statement = deleteFrom("test-data")
.where(x("name").eq(s("bob")).and(x("num").eq(s("10"))))
.returningRaw(meta(i("test-data")).get("id"));
You can make this statement parameterized or just execute like that.
I'm having a problem with MongoDB using Java when I try adding documents with customized _id field. And when I insert new document to that collection, I want to ignore the document if it's _id has already existed.
In Mongo shell, collection.save() can be used in this case but I cannot find the equivalent method to work with MongoDB java driver.
Just to add an example:
I have a collection of documents containing websites' information
with the URLs as _id field (which is unique)
I want to add some more documents. In those new documents, some might be existing in the current collection. So I want to keep adding all the new documents except for the duplicate ones.
This can be achieve by collection.save() in Mongo Shell but using MongoDB Java Driver, I can't find the equivalent method.
Hopefully someone can share the solution. Thanks in advance!
In the MongoDB Java driver, you could try using the BulkWriteOperation object with the initializeOrderedBulkOperation() method of the DBCollection object (the one that contains your collection). This is used as follows:
MongoClient mongo = new MongoClient("localhost", port_number);
DB db = mongo.getDB("db_name");
ArrayList<DBObject> objectList; // Fill this list with your objects to insert
BulkWriteOperation operation = col.initializeOrderedBulkOperation();
for (int i = 0; i < objectList.size(); i++) {
operation.insert(objectList.get(i));
}
BulkWriteResult result = operation.execute();
With this method, your documents will be inserted one at a time with error handling on each insert, so documents that have a duplicated id will throw an error as usual, but the operation will still continue with the rest of the documents. In the end, you can use the getInsertedCount() method of the BulkWriteResult object to know how many documents were really inserted.
This can prove to be a bit ineffective if lots of data is inserted this way, though. This is just sample code (that was found on journaldev.com and edited to fit your situation.). You may need to edit it so it fits your current configuration. It is also untested.
I guess save is doing something like this.
fun save(doc: Document, col: MongoCollection<Document>) {
if (doc.getObjectId("_id") != null) {
doc.put("_id", ObjectId()) // generate a new id
}
col.replaceOne(Document("_id", doc.getObjectId("_id")), doc)
}
Maybe they removed save so you decide how to generate the new id.
I'm using MongoDB 3.2 and want to avoid the duplicates in my collection. In order to do that I use createIndex() method (I tried different variants, none of them doesn't work):
dbColl.createIndex(new Document("guid", 1));
dbColl.createIndex(new BasicDBObject("guid", 1));
dbColl.createIndex(new Document("guid.content", 1));
dbColl.createIndex(new BasicDBObject("guid.content", 1));
Then I try to execute data insert with:
itemsArr.forEach(
item -> dbColl.insertOne(Document.parse(item.toString()))
);
I do it two times and anticipate that the second time MongoDB will not add any new row since the data has been already added and there is an index on the guid field. But that's not the case MongoDB adds duplicates despite index value.
Why does MongoDB add duplicates even if there is an index on a guid and/or guid.content field? And how to fix it? I want to be able to add the document with the same guid field only one time.
Here is a sample of documents structure:
In my data the guid field is a unique document identifier.
Regular indexes allow multiple documents with the same value.
What you need is not a regular index but an unique index. These are created by using the method createIndex(DBObject keys, DBObject options) with an options-object where unique is true.
collection.createIndex(new BasicDBObject("guid", 1), new BasicDBObject("unique", true));
With the help of Phillip, I composed a completely worked solution for the problem «How to avoid duplicates / skip duplicates on insert» in MongoDB 3.2 for Java Driver 3.2.0:
IndexOptions options = new IndexOptions();
// ensure the index is unique
options.unique(true);
// define the index
dbColl.createIndex(new BasicDBObject("guid", 1), options);
// add data to DB
for (Object item : itemsArr) {
// if there is a duplicate, skip it and write to a console (optionally)
try {
dbColl.insertOne(Document.parse(item.toString()));
} catch (com.mongodb.MongoWriteException ex) {
//System.err.println(ex.getMessage());
}
}
Feel free to use this ready-to-use solution.
I'm working with Java Apache Cayenne, under a MySQL DB.
I have quite a large table with a single bigint PK and some fields.
I'd like to retrieve just only the PK values and not all the object that maps this entity, as it would be too resource-consuming.
Is there a snippet that I can use, instead of this one that retrieves all the objects?
ObjectContext context = ...
SelectQuery select = new SelectQuery(MyClass.class);
List<MyClass> result = context.performQuery(select);
You should try using SQLTemplate instead of SelectQuery.
Here's a quick example:
ObjectContext context = ...
SQLTemplate select = new SQLTemplate(MyClass.class, "SELECT #result('PK_COLUMN' 'long') FROM MY_TABLE");
List result = context.performQuery(select);
You can find more information here
+1 for Josemando's answer. And here is another way that may work in case you are planning to only work with a subset of fetched objects:
ObjectContext context = ...
SelectQuery select = new SelectQuery(MyClass.class);
select.setPageSize(100);
List<MyClass> result = context.performQuery(select);
'setPageSize' ensures that 'result' only contains ids, until you attempt to read an object from the list. And when you do, it will resolve it page-by-page (100 objects at a time in the example above). This may fit a number of scenarios. Of course if you iterate through the entire list, eventually all objects will be fully resolved, and there will be no memory benefit.