【MarkLogic】「Java Client API」 による CRUD + α

# はじめに

「Java Client API」を使用して、MarkLogic上のデータ(JSON)を CRUD するコードを記載しています。

# 環境

* OS：Windows7 (64bit)
* java8
* MarkLogic (9.0-3.1)
* MarkLogic Java Client API (4.0.3)

# CRUD

基本的な CRUD です。

## ドキュメント作成 (Create)

新規にドキュメントを作成します。ドキュメントURIの生成はMarkLogicにやってもらいます。

```java:create
public class CreateApp {

	public static void main(String[] args) {
		CreateApp app = new CreateApp();
		app.execute(args);
	}

	private void execute(String[] args) {

		DatabaseClient client = createDatabaseClient();
		Transaction tran = client.openTransaction();

		try {
			String json = ""
					+ "{"
					+ "    \"aaa\" : \"AAA\","
					+ "    \"bbb\" : \"BBB\","
					+ "    \"ccc\" : 111,"
					+ "    \"ddd\" : ["
					+ "        {"
					+ "            \"ddd-1\" : \"DDD-1\","
					+ "            \"ddd-2\" : 11"
					+ "        },"
					+ "        {"
					+ "            \"ddd-1\" : \"DDD-2\","
					+ "            \"ddd-2\" : 22"
					+ "        }"
					+ "    ]"
					+ "}";

			create(client, json, tran);
			tran.commit();

		} catch (Exception ex) {
			tran.rollback();
			ex.printStackTrace();
		} finally {
			client.release();
		}
	}

	private String create(DatabaseClient client, String jsonData, Transaction tran) {
		JSONDocumentManager docMgr = client.newJSONDocumentManager();
		// 拡張子を指定
		DocumentUriTemplate uriTemplate = docMgr.newDocumentUriTemplate("json");
		// ディレクトリを指定
		uriTemplate.setDirectory("/xxx/yyy/");

		DocumentDescriptor desc = docMgr.create(uriTemplate, new StringHandle(jsonData), tran);
		// ドキュメントのURIを呼び出し元に返却
		return desc.getUri();
	}

	private DatabaseClient createDatabaseClient() {
		DatabaseClient client =
				DatabaseClientFactory.newClient(
						"xxx", 111, "xxx",
						new DigestAuthContext("xxx", "xxx"));
		return client;
	}
}
```

## ドキュメント検索＆読込 (Read)

QBEによる検索でURIを特定し、ドキュメントを読み込みます。

```java:read
public class ReadApp {

	public static void main(String[] args) {
		ReadApp app = new ReadApp();
		app.execute(args);
	}

	private void execute(String[] args) {

		DatabaseClient client = createDatabaseClient();

		try {
			String query = ""
					+ "{"
					+ "    \"$query\" : {"
					+ "        \"aaa\" : \"AAA\","
					+ "        \"bbb\" : \"BBB\","
					+ "        \"$filtered\" : false"
					+ "    }"
					+ "}";

			List<String> jsonList = search(client, "/xxx/yyy/", query, null);
			if (jsonList.isEmpty()) {
				return;
			}

			String uri = jsonList.get(0);
			String json = read(client, uri, null);
			System.out.println("____ uri  :" + uri);
			System.out.println("____ json :" + json);

		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			client.release();
		}
	}

	private List<String> search(DatabaseClient client, String dir, String query, Transaction tran) {

		QueryManager queryMgr = client.newQueryManager();
		queryMgr.setPageLength(100); // デフォルト 10件

		StringHandle strHandle = new StringHandle(query).withFormat(Format.JSON);
		RawQueryByExampleDefinition querydef = queryMgr.newRawQueryByExampleDefinition(strHandle);
		querydef.setDirectory(dir);

		SearchHandle searchHandle = queryMgr.search(querydef, new SearchHandle(), 1, tran, null);

		List<String> uriList = new ArrayList<String>();
		MatchDocumentSummary[] results = searchHandle.getMatchResults();
		for (MatchDocumentSummary summary : results) {
			uriList.add(summary.getUri());
		}

		return uriList;
	}

	private String read(DatabaseClient client, String uri, Transaction tran) {
		JSONDocumentManager docMgr = client.newJSONDocumentManager();
		String jsonData = docMgr.read(uri, new StringHandle(), tran).get();
		return jsonData;
	}

	private DatabaseClient createDatabaseClient() {
		//省略
	}
}
```

## ドキュメント検索＆更新 (Update)

QBEによる検索でURIを特定し、ドキュメントを更新(上書き)します。

```java:update
public class UpdateApp {

	public static void main(String[] args) {
		UpdateApp app = new UpdateApp();
		app.execute(args);
	}

	private void execute(String[] args) {

		DatabaseClient client = createDatabaseClient();
		Transaction tran = client.openTransaction();

		try {
			String query = ""
					+ "{"
					+ "    \"$query\" : {"
					+ "        \"aaa\" : \"AAA\","
					+ "        \"bbb\" : \"BBB\","
					+ "        \"$filtered\" : false"
					+ "    }"
					+ "}";

			String json = ""
					+ "{"
					+ "    \"aaa\" : \"AAAAAA\","
					+ "    \"bbb\" : \"BBBBBB\","
					+ "    \"ccc\" : 111111,"
					+ "    \"ddd\" : ["
					+ "        {"
					+ "            \"ddd-1\" : \"DDDDDD-1\","
					+ "            \"ddd-2\" : 1111"
					+ "        },"
					+ "        {"
					+ "            \"ddd-1\" : \"DDDDDD-2\","
					+ "            \"ddd-2\" : 2222"
					+ "        }"
					+ "    ]"
					+ "}";

			List<String> jsonList = search(client, "/xxx/yyy/", query, null);
			if (jsonList.isEmpty()) {
				return;
			}

			String uri = jsonList.get(0);
			update(client, uri, json, tran);
			tran.commit();

		} catch (Exception ex) {
			tran.rollback();
			ex.printStackTrace();
		} finally {
			client.release();
		}
	}

	private List<String> search(DatabaseClient client, String dir, String query, Transaction tran) {
		//省略
	}

	private void update(DatabaseClient client, String uri, String jsonData, Transaction tran) {
		JSONDocumentManager docMgr = client.newJSONDocumentManager();
		StringHandle strHandle = new StringHandle().with(jsonData);
		docMgr.write(uri, strHandle, tran);
	}

	private DatabaseClient createDatabaseClient() {
		//省略
	}
}
```

## ドキュメント検索＆削除 (Delete)

QBEによる検索でURIを特定し、ドキュメントを削除します。

```java:delete
public class DeleteApp {

	public static void main(String[] args) {
		DeleteApp app = new DeleteApp();
		app.execute(args);
	}

	private void execute(String[] args) {

		DatabaseClient client = createDatabaseClient();
		Transaction tran = client.openTransaction();

		try {
			String query = ""
					+ "{"
					+ "    \"$query\" : {"
					+ "        \"aaa\" : \"AAA\","
					+ "        \"bbb\" : \"BBB\","
					+ "        \"$filtered\" : false"
					+ "    }"
					+ "}";

			List<String> jsonList = search(client, "/xxx/yyy/", query, null);
			if (jsonList.isEmpty()) {
				return;
			}

			String uri = jsonList.get(0);
			delete(client, uri, tran);
			tran.commit();

		} catch (Exception ex) {
			tran.rollback();
			ex.printStackTrace();
		} finally {
			client.release();
		}
	}

	private List<String> search(DatabaseClient client, String dir, String query, Transaction tran) {
		//省略
	}

	private void delete(DatabaseClient client, String uri, Transaction tran) {
		JSONDocumentManager docMgr = client.newJSONDocumentManager();
		docMgr.delete(uri, tran);
	}

	private DatabaseClient createDatabaseClient() {
		//省略
	}
}
```

# +α

ドキュメントの一部のみを更新します。

## ドキュメントの部分更新 (値更新)

ドキュメント内のパスを指定して、値を更新します。

```java:値更新
public class PatchApp1 {

	public static void main(String[] args) {
		PatchApp1 app = new PatchApp1();
		app.execute(args);
	}

	private void execute(String[] args) {

		DatabaseClient client = createDatabaseClient();
		Transaction tran = client.openTransaction();

		try {
			String uri = "/xxx/yyy/zzz.json";
			patch(client, uri, "$.bbb", "XXXXXX", tran);
			tran.commit();

		} catch (Exception ex) {
			tran.rollback();
			ex.printStackTrace();
		} finally {
			client.release();
		}
	}

	private void patch(DatabaseClient client, String uri, String path, String value, Transaction tran) {

		JSONDocumentManager jsonMgr = client.newJSONDocumentManager();

		DocumentPatchBuilder patchBuilder = jsonMgr.newPatchBuilder().pathLanguage(PathLanguage.JSONPATH);
		patchBuilder.replaceValue(path, value);
		PatchHandle patchHandle = patchBuilder.build();

		jsonMgr.patch(uri, patchHandle, tran);
	}

	private DatabaseClient createDatabaseClient() {
		//省略
	}
}
```

## ドキュメントの部分更新 (配列要素に追加)

配列要素の末尾に要素を追加します。

```java:配列要素に追加
public class PatchApp2 {

	public static void main(String[] args) {
		PatchApp2 app = new PatchApp2();
		app.execute(args);
	}

	private void execute(String[] args) {

		DatabaseClient client = createDatabaseClient();
		Transaction tran = client.openTransaction();

		try {
			String uri = "/xxx/yyy/zzz.json";
			String fragment = ""
					+ "{"
					+ "    \"ddd-1\" : \"DDD-3\","
					+ "    \"ddd-2\" : 33"
					+ "}";
			patch(client, uri, "$.[\"ddd\"]", fragment, tran);
			tran.commit();

		} catch (Exception ex) {
			tran.rollback();
			ex.printStackTrace();
		} finally {
			client.release();
		}
	}

	private void patch(DatabaseClient client, String uri, String fragmentPath, String fragmentData, Transaction tran) {

		JSONDocumentManager jsonMgr = client.newJSONDocumentManager();

		DocumentPatchBuilder patchBuilder = jsonMgr.newPatchBuilder().pathLanguage(PathLanguage.JSONPATH);
		patchBuilder.insertFragment(fragmentPath, Position.LAST_CHILD, fragmentData);
		PatchHandle patchHandle = patchBuilder.build();

		jsonMgr.patch(uri, patchHandle, tran);
	}

	private DatabaseClient createDatabaseClient() {
		//省略
	}
}
```

## ドキュメントの部分更新 (配列要素を置換)

配列要素の内容をまるっと入れ替えます。

```java:配列要素を置換
public class PatchApp3 {

	public static void main(String[] args) {
		PatchApp3 app = new PatchApp3();
		app.execute(args);
	}

	private void execute(String[] args) {

		DatabaseClient client = createDatabaseClient();
		Transaction tran = client.openTransaction();

		try {
			String uri = "/xxx/yyy/zzz.json";
			String fragment = ""
					+ "[{"
					+ "    \"ddd-1\" : \"DDD-1\","
					+ "    \"ddd-2\" : 11"
					+ "}]";
			patch(client, uri, "$.[\"ddd\"]", fragment, tran);
			tran.commit();

		} catch (Exception ex) {
			tran.rollback();
			ex.printStackTrace();
		} finally {
			client.release();
		}
	}

	private void patch(DatabaseClient client, String uri, String path, String value, Transaction tran) {

		JSONDocumentManager jsonMgr = client.newJSONDocumentManager();

		DocumentPatchBuilder patchBuilder = jsonMgr.newPatchBuilder().pathLanguage(PathLanguage.JSONPATH);
		patchBuilder.replaceFragment(path, value);
		PatchHandle patchHandle = patchBuilder.build();

		jsonMgr.patch(uri, patchHandle, tran);
	}

	private DatabaseClient createDatabaseClient() {
		//省略
	}
}
```

以上