From 0d825983fa08032b1717576e808c05acf325b8b1 Mon Sep 17 00:00:00 2001
From: Shubham Mohole <95623059+Ishubhammohole@users.noreply.github.com>
Date: Mon, 14 Sep 2026 02:38:39 -0400
Subject: [PATCH 1/2] Add skip creation document option
---
.code-samples.meilisearch.yaml | 6 +-
.../java/com/meilisearch/sdk/Documents.java | 73 +++++++++++++++++
src/main/java/com/meilisearch/sdk/Index.java | 82 +++++++++++++++++++
.../sdk/DocumentsSkipCreationTest.java | 66 +++++++++++++++
4 files changed, 225 insertions(+), 2 deletions(-)
create mode 100644 src/test/java/com/meilisearch/sdk/DocumentsSkipCreationTest.java
diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml
index e3f0f8fe..7884f1eb 100644
--- a/.code-samples.meilisearch.yaml
+++ b/.code-samples.meilisearch.yaml
@@ -40,14 +40,16 @@ add_or_replace_documents_1: |-
+ "\"poster\": \"https://image.tmdb.org/t/p/w1280/xnopI5Xtky18MPhK40cZAGAOVeV.jpg\","
+ "\"overview\": \"A boy is given the ability to become an adult superhero in times of need with a single magic word.\","
+ "\"release_date\": \"2019-03-23\""
- + "}]"
+ + "}]",
+ true
);
add_or_update_documents_1: |-
client.index("movies").updateDocuments("[{
+ "\"id\": 287947,"
+ "\"title\": \"Shazam ⚡️\","
+ "\"genres\": \"comedy\""
- + "}]"
+ + "}]",
+ true
);
delete_all_documents_1: |-
client.index("movies").deleteAllDocuments();
diff --git a/src/main/java/com/meilisearch/sdk/Documents.java b/src/main/java/com/meilisearch/sdk/Documents.java
index ce671fba..eba221ea 100644
--- a/src/main/java/com/meilisearch/sdk/Documents.java
+++ b/src/main/java/com/meilisearch/sdk/Documents.java
@@ -182,6 +182,41 @@ TaskInfo addDocuments(
String csvDelimiter,
String customMetadata)
throws MeilisearchException {
+ return addDocumentsRequest(uid, document, primaryKey, csvDelimiter, customMetadata, null);
+ }
+
+ /**
+ * Adds/Replaces a document at the specified index uid
+ *
+ * @param uid Partial index identifier for the document
+ * @param document String containing the document to add
+ * @param primaryKey PrimaryKey of the document
+ * @param csvDelimiter CSV delimiter of the document
+ * @param customMetadata Custom metadata to attach to the task
+ * @param skipCreation Whether to skip creating documents that do not already exist
+ * @return Meilisearch's TaskInfo API response
+ * @throws MeilisearchException if the client request causes an error
+ */
+ TaskInfo addDocuments(
+ String uid,
+ String document,
+ String primaryKey,
+ String csvDelimiter,
+ String customMetadata,
+ boolean skipCreation)
+ throws MeilisearchException {
+ return addDocumentsRequest(
+ uid, document, primaryKey, csvDelimiter, customMetadata, skipCreation);
+ }
+
+ private TaskInfo addDocumentsRequest(
+ String uid,
+ String document,
+ String primaryKey,
+ String csvDelimiter,
+ String customMetadata,
+ Boolean skipCreation)
+ throws MeilisearchException {
URLBuilder urlb = documentPath(uid);
if (primaryKey != null) {
urlb.addParameter("primaryKey", primaryKey);
@@ -192,6 +227,7 @@ TaskInfo addDocuments(
if (customMetadata != null) {
urlb.addParameter("customMetadata", customMetadata);
}
+ urlb.addParameter("skipCreation", skipCreation);
return httpClient.post(urlb.getURL(), document, TaskInfo.class);
}
@@ -227,6 +263,42 @@ TaskInfo updateDocuments(
String csvDelimiter,
String customMetadata)
throws MeilisearchException {
+ return updateDocumentsRequest(
+ uid, document, primaryKey, csvDelimiter, customMetadata, null);
+ }
+
+ /**
+ * Updates documents at the specified index uid
+ *
+ * @param uid Partial index identifier for the document
+ * @param document String containing the document to update
+ * @param primaryKey PrimaryKey of the document
+ * @param csvDelimiter CSV delimiter of the document
+ * @param customMetadata Custom metadata to attach to the task
+ * @param skipCreation Whether to skip creating documents that do not already exist
+ * @return Meilisearch's TaskInfo API response
+ * @throws MeilisearchException if the client request causes an error
+ */
+ TaskInfo updateDocuments(
+ String uid,
+ String document,
+ String primaryKey,
+ String csvDelimiter,
+ String customMetadata,
+ boolean skipCreation)
+ throws MeilisearchException {
+ return updateDocumentsRequest(
+ uid, document, primaryKey, csvDelimiter, customMetadata, skipCreation);
+ }
+
+ private TaskInfo updateDocumentsRequest(
+ String uid,
+ String document,
+ String primaryKey,
+ String csvDelimiter,
+ String customMetadata,
+ Boolean skipCreation)
+ throws MeilisearchException {
URLBuilder urlb = documentPath(uid);
if (primaryKey != null) {
urlb.addParameter("primaryKey", primaryKey);
@@ -237,6 +309,7 @@ TaskInfo updateDocuments(
if (customMetadata != null) {
urlb.addParameter("customMetadata", customMetadata);
}
+ urlb.addParameter("skipCreation", skipCreation);
return httpClient.put(urlb.getURL(), document, TaskInfo.class);
}
diff --git a/src/main/java/com/meilisearch/sdk/Index.java b/src/main/java/com/meilisearch/sdk/Index.java
index 97d397b7..2fdf2d55 100644
--- a/src/main/java/com/meilisearch/sdk/Index.java
+++ b/src/main/java/com/meilisearch/sdk/Index.java
@@ -172,6 +172,22 @@ public TaskInfo addDocuments(String document) throws MeilisearchException {
return this.documents.addDocuments(this.uid, document, null, null);
}
+ /**
+ * Adds/Replaces documents in the index
+ *
+ * @param document Document to add in JSON string format
+ * @param skipCreation Whether to skip creating documents that do not already exist
+ * @return TaskInfo Meilisearch API response
+ * @throws MeilisearchException if an error occurs
+ * @see API
+ * specification
+ */
+ public TaskInfo addDocuments(String document, boolean skipCreation)
+ throws MeilisearchException {
+ return this.documents.addDocuments(this.uid, document, null, null, null, skipCreation);
+ }
+
/**
* Adds/Replaces documents in the index
*
@@ -224,6 +240,31 @@ public TaskInfo addDocuments(
this.uid, document, primaryKey, csvDelimiter, customMetadata);
}
+ /**
+ * Adds/Replaces documents in the index
+ *
+ * @param document Document to add in JSON or CSV string format
+ * @param primaryKey PrimaryKey of the document to add
+ * @param csvDelimiter Custom delimiter to use for the document being added
+ * @param customMetadata Custom metadata to attach to the task
+ * @param skipCreation Whether to skip creating documents that do not already exist
+ * @return TaskInfo Meilisearch API response
+ * @throws MeilisearchException if an error occurs
+ * @see API
+ * specification
+ */
+ public TaskInfo addDocuments(
+ String document,
+ String primaryKey,
+ String csvDelimiter,
+ String customMetadata,
+ boolean skipCreation)
+ throws MeilisearchException {
+ return this.documents.addDocuments(
+ this.uid, document, primaryKey, csvDelimiter, customMetadata, skipCreation);
+ }
+
/**
* Adds/Replaces documents in the index in batches
*
@@ -285,6 +326,22 @@ public TaskInfo updateDocuments(String document) throws MeilisearchException {
return this.documents.updateDocuments(this.uid, document, null, null);
}
+ /**
+ * Updates documents in the index
+ *
+ * @param document Document to update in JSON string format
+ * @param skipCreation Whether to skip creating documents that do not already exist
+ * @return TaskInfo Meilisearch API response
+ * @throws MeilisearchException if an error occurs
+ * @see API
+ * specification
+ */
+ public TaskInfo updateDocuments(String document, boolean skipCreation)
+ throws MeilisearchException {
+ return this.documents.updateDocuments(this.uid, document, null, null, null, skipCreation);
+ }
+
/**
* Updates documents in the index
*
@@ -338,6 +395,31 @@ public TaskInfo updateDocuments(
this.uid, document, primaryKey, csvDelimiter, customMetadata);
}
+ /**
+ * Updates documents in the index
+ *
+ * @param document Document to update in JSON or CSV string format
+ * @param primaryKey PrimaryKey of the document
+ * @param csvDelimiter Custom delimiter to use for the document being updated
+ * @param customMetadata Custom metadata to attach to the task
+ * @param skipCreation Whether to skip creating documents that do not already exist
+ * @return TaskInfo Meilisearch API response
+ * @throws MeilisearchException if an error occurs
+ * @see API
+ * specification
+ */
+ public TaskInfo updateDocuments(
+ String document,
+ String primaryKey,
+ String csvDelimiter,
+ String customMetadata,
+ boolean skipCreation)
+ throws MeilisearchException {
+ return this.documents.updateDocuments(
+ this.uid, document, primaryKey, csvDelimiter, customMetadata, skipCreation);
+ }
+
/**
* Updates documents in index in batches
*
diff --git a/src/test/java/com/meilisearch/sdk/DocumentsSkipCreationTest.java b/src/test/java/com/meilisearch/sdk/DocumentsSkipCreationTest.java
new file mode 100644
index 00000000..06cc7ecb
--- /dev/null
+++ b/src/test/java/com/meilisearch/sdk/DocumentsSkipCreationTest.java
@@ -0,0 +1,66 @@
+package com.meilisearch.sdk;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
+import okhttp3.mockwebserver.RecordedRequest;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class DocumentsSkipCreationTest {
+
+ private MockWebServer server;
+ private Index index;
+
+ @BeforeEach
+ void setup() throws Exception {
+ server = new MockWebServer();
+ server.start();
+
+ Client client = new Client(new Config(server.url("/").toString(), "masterKey"));
+ index = client.index("movies");
+ }
+
+ @AfterEach
+ void teardown() throws Exception {
+ server.shutdown();
+ }
+
+ @Test
+ void addDocumentsIncludesSkipCreation() throws Exception {
+ server.enqueue(new MockResponse().setBody("{\"taskUid\": 1}").setResponseCode(202));
+
+ index.addDocuments("[]", true);
+
+ RecordedRequest request = server.takeRequest();
+ assertThat(request.getMethod(), equalTo("POST"));
+ assertThat(request.getPath(), equalTo("//indexes/movies/documents?skipCreation=true"));
+ }
+
+ @Test
+ void updateDocumentsIncludesSkipCreationAndExistingParameters() throws Exception {
+ server.enqueue(new MockResponse().setBody("{\"taskUid\": 2}").setResponseCode(202));
+
+ index.updateDocuments("[]", "id", ";", "import", false);
+
+ RecordedRequest request = server.takeRequest();
+ assertThat(request.getMethod(), equalTo("PUT"));
+ assertThat(
+ request.getPath(),
+ equalTo(
+ "//indexes/movies/documents?primaryKey=id&csvDelimiter=;&customMetadata=import&skipCreation=false"));
+ }
+
+ @Test
+ void existingDocumentMethodsOmitSkipCreation() throws Exception {
+ server.enqueue(new MockResponse().setBody("{\"taskUid\": 3}").setResponseCode(202));
+
+ index.addDocuments("[]");
+
+ RecordedRequest request = server.takeRequest();
+ assertThat(request.getPath(), equalTo("//indexes/movies/documents"));
+ }
+}
From 95e049c33eb8763e0b6591cdf6e8d9ff32c1fb76 Mon Sep 17 00:00:00 2001
From: Shubham Mohole <95623059+Ishubhammohole@users.noreply.github.com>
Date: Sat, 19 Sep 2026 16:37:45 -0400
Subject: [PATCH 2/2] Document skipCreation request helpers and regression
tests
---
.../java/com/meilisearch/sdk/Documents.java | 24 +++++++++++++++++++
.../sdk/DocumentsSkipCreationTest.java | 7 ++++++
2 files changed, 31 insertions(+)
diff --git a/src/main/java/com/meilisearch/sdk/Documents.java b/src/main/java/com/meilisearch/sdk/Documents.java
index eba221ea..cdaf8dc4 100644
--- a/src/main/java/com/meilisearch/sdk/Documents.java
+++ b/src/main/java/com/meilisearch/sdk/Documents.java
@@ -209,6 +209,18 @@ TaskInfo addDocuments(
uid, document, primaryKey, csvDelimiter, customMetadata, skipCreation);
}
+ /**
+ * Sends an add/replace request, preserving the server default when skipCreation is null.
+ *
+ * @param uid Index identifier
+ * @param document Serialized documents to add or replace
+ * @param primaryKey Optional primary key
+ * @param csvDelimiter Optional CSV delimiter
+ * @param customMetadata Optional task metadata
+ * @param skipCreation Whether to skip new documents, or null to omit the parameter
+ * @return Enqueued task information
+ * @throws MeilisearchException if the request fails
+ */
private TaskInfo addDocumentsRequest(
String uid,
String document,
@@ -291,6 +303,18 @@ TaskInfo updateDocuments(
uid, document, primaryKey, csvDelimiter, customMetadata, skipCreation);
}
+ /**
+ * Sends an update request, preserving the server default when skipCreation is null.
+ *
+ * @param uid Index identifier
+ * @param document Serialized documents to update
+ * @param primaryKey Optional primary key
+ * @param csvDelimiter Optional CSV delimiter
+ * @param customMetadata Optional task metadata
+ * @param skipCreation Whether to skip new documents, or null to omit the parameter
+ * @return Enqueued task information
+ * @throws MeilisearchException if the request fails
+ */
private TaskInfo updateDocumentsRequest(
String uid,
String document,
diff --git a/src/test/java/com/meilisearch/sdk/DocumentsSkipCreationTest.java b/src/test/java/com/meilisearch/sdk/DocumentsSkipCreationTest.java
index 06cc7ecb..95c80544 100644
--- a/src/test/java/com/meilisearch/sdk/DocumentsSkipCreationTest.java
+++ b/src/test/java/com/meilisearch/sdk/DocumentsSkipCreationTest.java
@@ -15,6 +15,9 @@ class DocumentsSkipCreationTest {
private MockWebServer server;
private Index index;
+ /**
+ * Starts an isolated HTTP server so requests can be inspected without a Meilisearch instance.
+ */
@BeforeEach
void setup() throws Exception {
server = new MockWebServer();
@@ -24,11 +27,13 @@ void setup() throws Exception {
index = client.index("movies");
}
+ /** Releases the server and its connections after each test. */
@AfterEach
void teardown() throws Exception {
server.shutdown();
}
+ /** Verifies the short add/replace overload sends an explicit true value. */
@Test
void addDocumentsIncludesSkipCreation() throws Exception {
server.enqueue(new MockResponse().setBody("{\"taskUid\": 1}").setResponseCode(202));
@@ -40,6 +45,7 @@ void addDocumentsIncludesSkipCreation() throws Exception {
assertThat(request.getPath(), equalTo("//indexes/movies/documents?skipCreation=true"));
}
+ /** Verifies false is not omitted and existing update parameters are preserved. */
@Test
void updateDocumentsIncludesSkipCreationAndExistingParameters() throws Exception {
server.enqueue(new MockResponse().setBody("{\"taskUid\": 2}").setResponseCode(202));
@@ -54,6 +60,7 @@ void updateDocumentsIncludesSkipCreationAndExistingParameters() throws Exception
"//indexes/movies/documents?primaryKey=id&csvDelimiter=;&customMetadata=import&skipCreation=false"));
}
+ /** Verifies legacy overloads leave skipCreation unspecified for backward compatibility. */
@Test
void existingDocumentMethodsOmitSkipCreation() throws Exception {
server.enqueue(new MockResponse().setBody("{\"taskUid\": 3}").setResponseCode(202));