Я хочу обрабатывать уведомления, как только они добавляются в MongoDB. Для этого существуют закрытые коллекции, которые позволяют использовать настраиваемые курсоры. Они должны блокироваться при получении следующего элемента, пока этот следующий элемент не станет доступным.
Вот код Go, который я использовал:
package main
import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
"time"
)
func main() {
defer fmt.Println("done.")
ctx := context.Background()
collection, err := connect(ctx)
if err != nil {
fmt.Println("failed to connect", err)
return
}
fmt.Println("connected.")
if err := follow(ctx, collection); err != nil {
fmt.Println("failed to follow", err)
}
}
func connect(ctx context.Context) (*mongo.Collection, error) {
// use 3s timeout for connecting
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()
opts := options.Client().
ApplyURI("mongodb://localhost")
err := opts.Validate()
if err != nil {
return nil, err
}
client, err := mongo.NewClient(opts)
if err != nil {
return nil, err
}
if err := client.Connect(ctx); err != nil {
return nil, err
}
if err := client.Ping(ctx, readpref.Primary()); err != nil {
return nil, err
}
db := client.Database("test")
return db.Collection("example"), nil
}
func follow(ctx context.Context, collection *mongo.Collection) error {
// create a tailable cursor on the collection
filter := bson.M{}
opts := options.Find().
SetCursorType(options.TailableAwait)
cursor, err := collection.Find(ctx, filter, opts)
if err != nil {
return err
}
defer cursor.Close(ctx)
// load and print documents as they are inserted
for cursor.Next(ctx) {
var document bson.M
if err := cursor.Decode(&document); err != nil {
return err
}
fmt.Println("loaded document", document)
}
return nil
}
MongoDB был настроен с использованием Docker, посмотрите скрипт Bash:
docker run --rm --detach --name mongodb --publish 27017:27017 mongo:4.2
sleep 2 # Hack: wait for the DB to start up
docker exec mongodb mongo --eval "db.createCollection('example', {capped:true, size: 1000000})"
При запуске программы Go появляется следующий вывод:
connected.
done.
Здесь есть две особенности: во-первых, я бы ожидать, что это заблокирует после подключения, то есть никогда не выходить. Во-вторых, нет даже ошибки!
Если вы запустите docker exec mongodb mongo --eval "db.example.insert({_id:1})"
просто для добавления некоторого содержимого в коллекцию, это изменит поведение программы. Затем, после подключения, он выводит существующий элемент и затем сидит там:
connected.
loaded document map[_id:1]
Я делаю что-то не так или это ошибка в другом месте?