MongoDBを使用した単純なタグ付けの実装
1. 概要
このチュートリアルでは、JavaとMongoDBを使用した簡単なタグ付けの実装を見ていきます。
概念に慣れていない人にとって、タグは、ドキュメントをさまざまなカテゴリにグループ化するための「ラベル」として使用されるキーワードです。これにより、ユーザーは類似したコンテンツをすばやくナビゲートでき、大きなものを扱うときに特に役立ちます。データの量。
そうは言っても、この手法がブログで非常に一般的に使用されているのは当然のことです。 このシナリオでは、各投稿には、対象となるトピックに応じて1つ以上のタグがあります。 ユーザーが読み終えたら、タグの1つをたどって、そのトピックに関連するその他のコンテンツを表示できます。
このシナリオを実装する方法を見てみましょう。
2. 依存
データベースをクエリするには、MongoDBドライバーの依存関係をpom.xmlに含める必要があります。
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.6.3</version>
</dependency>
この依存関係の現在のバージョンは、ここにあります。
3. データ・モデル
まず、投稿ドキュメントがどのようになるかを計画することから始めましょう。
簡単にするために、データモデルにはタイトルのみが含まれます。これは、ドキュメントID、作成者、およびいくつかのタグとしても使用されます。
投稿にはおそらく複数のタグが含まれるため、タグを配列内に格納します。
{
"_id" : "Java 8 and MongoDB",
"author" : "Donato Rimenti",
"tags" : ["Java", "MongoDB", "Java 8", "Stream API"]
}
対応するJavaモデルクラスも作成します。
public class Post {
private String title;
private String author;
private List<String> tags;
// getters and setters
}
4. タグの更新
データベースを設定し、いくつかのサンプル投稿を挿入したので、それらを更新する方法を見てみましょう。
リポジトリクラスには、タイトルを使用してタグを検索することにより、タグの追加と削除を処理する2つのメソッドが含まれます。 また、クエリが要素を更新したかどうかを示すブール値を返します。
public boolean addTags(String title, List<String> tags) {
UpdateResult result = collection.updateOne(
new BasicDBObject(DBCollection.ID_FIELD_NAME, title),
Updates.addEachToSet(TAGS_FIELD, tags));
return result.getModifiedCount() == 1;
}
public boolean removeTags(String title, List<String> tags) {
UpdateResult result = collection.updateOne(
new BasicDBObject(DBCollection.ID_FIELD_NAME, title),
Updates.pullAll(TAGS_FIELD, tags));
return result.getModifiedCount() == 1;
}
追加にはpushの代わりにaddEachToSetメソッドを使用したため、タグがすでに存在する場合は、再度追加することはありません。
また、 addToSet 演算子は、新しいタグをネストされた配列として追加するため、機能しないことにも注意してください。これは、必要なものではありません。
更新を実行するもう1つの方法は、Mongoシェルを使用することです。たとえば、投稿 JUnit5をJavaで更新しましょう。特に、タグを追加します。 JavaとJUnit5 を削除し、タグSpringとRESTを削除します。
db.posts.updateOne(
{ _id : "JUnit 5 with Java" },
{ $addToSet :
{ "tags" :
{ $each : ["Java", "JUnit5"] }
}
});
db.posts.updateOne(
{_id : "JUnit 5 with Java" },
{ $pull :
{ "tags" : { $in : ["Spring", "REST"] }
}
});
5. クエリ
最後になりましたが、タグの操作中に関心を持つ可能性のある最も一般的なクエリのいくつかを見ていきましょう。 この目的のために、特に3つの配列演算子を利用します。
- $ in – は、フィールドに指定された配列の任意の値が含まれているドキュメントを返します
- $ nin – は、フィールドに指定された配列の値が含まれていないドキュメントを返します
- $ all – は、フィールドに指定された配列のすべての値が含まれているドキュメントを返します
引数として渡されたタグのコレクションに関連して投稿をクエリする3つのメソッドを定義します。 少なくとも1つのタグ、すべてのタグに一致し、どのタグにも一致しない投稿を返します。 また、Java8のStreamAPIを使用して、ドキュメントとモデル間の変換を処理するマッピングメソッドを作成します。
public List<Post> postsWithAtLeastOneTag(String... tags) {
FindIterable<Document> results = collection
.find(Filters.in(TAGS_FIELD, tags));
return StreamSupport.stream(results.spliterator(), false)
.map(TagRepository::documentToPost)
.collect(Collectors.toList());
}
public List<Post> postsWithAllTags(String... tags) {
FindIterable<Document> results = collection
.find(Filters.all(TAGS_FIELD, tags));
return StreamSupport.stream(results.spliterator(), false)
.map(TagRepository::documentToPost)
.collect(Collectors.toList());
}
public List<Post> postsWithoutTags(String... tags) {
FindIterable<Document> results = collection
.find(Filters.nin(TAGS_FIELD, tags));
return StreamSupport.stream(results.spliterator(), false)
.map(TagRepository::documentToPost)
.collect(Collectors.toList());
}
private static Post documentToPost(Document document) {
Post post = new Post();
post.setTitle(document.getString(DBCollection.ID_FIELD_NAME));
post.setAuthor(document.getString("author"));
post.setTags((List<String>) document.get(TAGS_FIELD));
return post;
}
繰り返しになりますが、シェルと同等のクエリも見てみましょう。 MongoDBまたはStream APIでそれぞれタグ付けされ、 Java8とJUnit5の両方でタグ付けされた3つの異なる投稿コレクションをフェッチします。 GroovyまたはScalaでタグ付けされていない:
db.posts.find({
"tags" : { $in : ["MongoDB", "Stream API" ] }
});
db.posts.find({
"tags" : { $all : ["Java 8", "JUnit 5" ] }
});
db.posts.find({
"tags" : { $nin : ["Groovy", "Scala" ] }
});
6. 結論
この記事では、タグ付けメカニズムを構築する方法を示しました。 もちろん、ブログ以外の目的でも、これと同じ方法を使用して再適応させることができます。
MongoDBの学習にさらに興味がある場合は、この紹介記事を読むことをお勧めします。
いつものように、例のすべてのコードは、Githubプロジェクトで利用できます。