如何在Mongodb中创建一个唯一的索引对?

huangapple go评论69阅读模式
英文:

How to create an index of pair unique for Mongodb?

问题

我正在使用MongoDB工作,我想在两个字段上创建一个唯一的键对。

以下是我目前所做的:

func (repository *TranslationRepository) createIndexes(collection *mongo.Collection) error {
	models := []mongo.IndexModel{
		{
			Keys:    bson.D{{"object_id", 1}, {"object_type", 1}},
			Options: options.Index().SetUnique(true),
		},
		{
			Keys:    bson.D{{"expire_at", 1}},
			Options: options.Index().SetExpireAfterSeconds(0),
		},
	}

	opts := options.CreateIndexes().SetMaxTime(10 * time.Second)
	_, err := collection.Indexes().CreateMany(context.Background(), models, opts)
	return err
}

然而,当我像这样插入两条记录时:

{
    "object_id"  : "abc",
    "object_type": "SAMPLE" 
}

{
    "object_id"  : "edf",
    "object_type": "SAMPLE" 
}

在数据库中,只会有一条记录:

{
    "object_id"  : "edf",
    "object_type": "SAMPLE" 
}

第二条记录已经覆盖了第一条记录。

以下是我插入记录的示例代码:

TranslationForm := entity.TranslationForm{
	ObjectID:       "ABC",
	ObjectType:     "SAMPLE",
	SourceLanguage: "en",
	TargetLanguage: "cn",
	Content:        "something",
	ExpireAt:       time.Now(),
}
res, err := repository.collection.InsertOne(context.TODO(), TranslationForm)
英文:

I am working with MongoDB, I want to make a pair unique on 2 field.

The below is what I have done so far :

func (repository *TranslationRepository) createIndexes(collection *mongo.Collection) error {
	models := []mongo.IndexModel{
		{
			Keys:    bson.D{{"object_id", 1}, {"object_type", 1}},
			Options: options.Index().SetUnique(true),
		},
		{
			Keys:    bson.D{{"expire_at", 1}},
			Options: options.Index().SetExpireAfterSeconds(0),
		},
	}

	opts := options.CreateIndexes().SetMaxTime(10 * time.Second)
	_, err := collection.Indexes().CreateMany(context.Background(), models, opts)
	return err
}

However when I insert 2 records like this

{
    "object_id"  : "abc",
    "object_type": "SAMPLE" 
}

{
    "object_id"  : "edf",
    "object_type": "SAMPLE" 
}

In the database, there will be only 1 record of

{
    "object_id"  : "edf",
    "object_type": "SAMPLE" 
}

The second already overwrited the first

The below is my sample code of inserting a record

TranslationForm := entity.TranslationForm{
		ObjectID:       "ABC",
		ObjectType:     "SAMPLE",
		SourceLanguage: "en",
		TargetLanguage: "cn",
		Content:        "something",
		ExpireAt:       time.Now(),
	}
res, err := repository.collection.InsertOne(context.TODO(), TranslationForm)

答案1

得分: 1

我应该管理你的情景。让我分享一个简单的程序来展示我所实现的内容。

package main

import (
	"context"
	"fmt"
	"time"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type Object struct {
	ObjectId   string `json:"object_id" bson:"object_id"`
	ObjectType string `json:"object_type" bson:"object_type"`
}

func main() {
	ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*10)
	defer cancelFunc()

	clientOptions := options.Client().ApplyURI("mongodb://root:root@localhost:27017")
	mongoClient, err := mongo.Connect(ctx, clientOptions)
	if err != nil {
		panic(err)
	}
	defer mongoClient.Disconnect(ctx)

	demoDb := mongoClient.Database("demodb")
	defer demoDb.Drop(ctx)
	myCollection := demoDb.Collection("myCollection")
	defer myCollection.Drop(ctx)

	// 创建索引
	indexModel := mongo.IndexModel{
		Keys: bson.D{
			bson.E{
				Key:   "object_id",
				Value: 1,
			},
			bson.E{
				Key:   "object_type",
				Value: 1,
			},
		},
		Options: options.Index().SetUnique(true),
	}
	idxName, err := myCollection.Indexes().CreateOne(ctx, indexModel)
	if err != nil {
		panic(err)
	}

	fmt.Println("索引名称:", idxName)

	// 删除文档
	defer func() {
		if _, err := myCollection.DeleteMany(ctx, bson.M{}); err != nil {
			panic(err)
		}
	}()

	// 插入第一个文档
	res, err := myCollection.InsertOne(ctx, Object{ObjectId: "abc", ObjectType: "SAMPLE"})
	if err != nil {
		panic(err)
	}
	fmt.Println(res.InsertedID)

	// 插入第二个文档
	// res, err = myCollection.InsertOne(ctx, Object{ObjectId: "abc", ObjectType: "SAMPLE"}) => ERROR
	res, err = myCollection.InsertOne(ctx, Object{ObjectId: "def", ObjectType: "SAMPLE"}) // => OK!
	if err != nil {
		panic(err)
	}
	fmt.Println(res.InsertedID)

	// 列出所有文档
	var objects []Object
	cursor, err := myCollection.Find(ctx, bson.M{})
	if err != nil {
		panic(err)
	}
	if err = cursor.All(ctx, &objects); err != nil {
		panic(err)
	}
	fmt.Println(objects)
}

现在,我将总结所有的主要步骤:

  1. 定义了Object结构体,它是你所需的简化版本。请注意bson注释是实际使用的注释。为了演示的目的,你可以安全地忽略json注释。
  2. 与Mongo生态系统相关的设置:
    • 创建上下文(带有超时)
    • 客户端设置(连接到通过Docker运行的本地MongoDB实例)
    • 创建名为demodb的数据库和名为myCollection的集合。此外,我还延迟了在程序退出时删除这些内容的调用(仅用于清理)。
  3. object_idobject_type字段上创建唯一的复合索引。请注意Options字段,它使用SetUnique方法声明了索引的唯一性。
  4. 添加文档。请注意,程序不允许插入具有相同字段的两个文档,你可以尝试注释/取消注释这些情况以进行确认。
  5. 最后,为了调试目的,我列出了集合中的文档,以检查第二个文档是否已添加。

希望这个演示能够解答你的疑问。如果有任何问题,请告诉我,谢谢!

英文:

I should have managed your scenario. Let me share a simple program to show off what I achieved.

package main

import (
	"context"
	"fmt"
	"time"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type Object struct {
	ObjectId   string `json:"object_id" bson:"object_id"`
	ObjectType string `json:"object_type" bson:"object_type"`
}

func main() {
	ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*10)
	defer cancelFunc()

	clientOptions := options.Client().ApplyURI("mongodb://root:root@localhost:27017")
	mongoClient, err := mongo.Connect(ctx, clientOptions)
	if err != nil {
		panic(err)
	}
	defer mongoClient.Disconnect(ctx)

	demoDb := mongoClient.Database("demodb")
	defer demoDb.Drop(ctx)
	myCollection := demoDb.Collection("myCollection")
	defer myCollection.Drop(ctx)

	// create index
	indexModel := mongo.IndexModel{
		Keys: bson.D{
			bson.E{
				Key:   "object_id",
				Value: 1,
			},
			bson.E{
				Key:   "object_type",
				Value: 1,
			},
		},
		Options: options.Index().SetUnique(true),
	}
	idxName, err := myCollection.Indexes().CreateOne(ctx, indexModel)
	if err != nil {
		panic(err)
	}

	fmt.Println("index name:", idxName)

	// delete documents
	defer func() {
		if _, err := myCollection.DeleteMany(ctx, bson.M{}); err != nil {
			panic(err)
		}
	}()

	// insert first doc
	res, err := myCollection.InsertOne(ctx, Object{ObjectId: "abc", ObjectType: "SAMPLE"})
	if err != nil {
		panic(err)
	}
	fmt.Println(res.InsertedID)

	// insert second doc
	// res, err = myCollection.InsertOne(ctx, Object{ObjectId: "abc", ObjectType: "SAMPLE"}) => ERROR
	res, err = myCollection.InsertOne(ctx, Object{ObjectId: "def", ObjectType: "SAMPLE"}) // => OK!
	if err != nil {
		panic(err)
	}
	fmt.Println(res.InsertedID)

	// list all docs
	var objects []Object
	cursor, err := myCollection.Find(ctx, bson.M{})
	if err != nil {
		panic(err)
	}
	if err = cursor.All(ctx, &objects); err != nil {
		panic(err)
	}
	fmt.Println(objects)
}

Now, I'm gonna recap all of the main steps:

  1. Definition of the Object struct which is a simplified version of what you need. Please note the bson annotations that are the ones actually used. For the sake of this demo, you can safely omit the json ones.
  2. The setup related to the Mongo ecosystem:
    1. Context creation (with a timeout)
    2. Client set up (connection to a local MongoDB instance run via Docker)
    3. Creation of a database called demodb and a collection called myCollection. Plus, I deferred the calls to delete this stuff while exiting the programs (just for clean-up).
  3. Creation of a unique compound index on the fields object_id and object_type. Pay attention to the Options field that states the uniqueness of the index with the method SetUnique.
  4. Adding documents. Please note that the program won't allow you to insert two documents with the same fields as requested. You can try to comment/uncomment the cases just to have another confirmation.
  5. For debug purposes, I finally list the documents in the collection to check whether the second document has been added or not.

I hope that this demo has clarified a few your doubts. Let me know & thanks!

huangapple
  • 本文由 发表于 2023年4月14日 12:48:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/76011686.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定