...

Source file src/go.mongodb.org/mongo-driver/mongo/search_index_view.go

Documentation: go.mongodb.org/mongo-driver/mongo

     1  // Copyright (C) MongoDB, Inc. 2023-present.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License"); you may
     4  // not use this file except in compliance with the License. You may obtain
     5  // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
     6  
     7  package mongo
     8  
     9  import (
    10  	"context"
    11  	"fmt"
    12  	"strconv"
    13  
    14  	"go.mongodb.org/mongo-driver/bson"
    15  	"go.mongodb.org/mongo-driver/mongo/options"
    16  	"go.mongodb.org/mongo-driver/mongo/writeconcern"
    17  	"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
    18  	"go.mongodb.org/mongo-driver/x/mongo/driver"
    19  	"go.mongodb.org/mongo-driver/x/mongo/driver/operation"
    20  	"go.mongodb.org/mongo-driver/x/mongo/driver/session"
    21  )
    22  
    23  // SearchIndexView is a type that can be used to create, drop, list and update search indexes on a collection. A SearchIndexView for
    24  // a collection can be created by a call to Collection.SearchIndexes().
    25  type SearchIndexView struct {
    26  	coll *Collection
    27  }
    28  
    29  // SearchIndexModel represents a new search index to be created.
    30  type SearchIndexModel struct {
    31  	// A document describing the definition for the search index. It cannot be nil.
    32  	// See https://www.mongodb.com/docs/atlas/atlas-search/create-index/ for reference.
    33  	Definition interface{}
    34  
    35  	// The search index options.
    36  	Options *options.SearchIndexesOptions
    37  }
    38  
    39  // List executes a listSearchIndexes command and returns a cursor over the search indexes in the collection.
    40  //
    41  // The name parameter specifies the index name. A nil pointer matches all indexes.
    42  //
    43  // The opts parameter can be used to specify options for this operation (see the options.ListSearchIndexesOptions
    44  // documentation).
    45  func (siv SearchIndexView) List(
    46  	ctx context.Context,
    47  	searchIdxOpts *options.SearchIndexesOptions,
    48  	opts ...*options.ListSearchIndexesOptions,
    49  ) (*Cursor, error) {
    50  	if ctx == nil {
    51  		ctx = context.Background()
    52  	}
    53  
    54  	index := bson.D{}
    55  	if searchIdxOpts != nil && searchIdxOpts.Name != nil {
    56  		index = bson.D{{"name", *searchIdxOpts.Name}}
    57  	}
    58  
    59  	aggregateOpts := make([]*options.AggregateOptions, len(opts))
    60  	for i, opt := range opts {
    61  		aggregateOpts[i] = opt.AggregateOpts
    62  	}
    63  
    64  	return siv.coll.Aggregate(ctx, Pipeline{{{"$listSearchIndexes", index}}}, aggregateOpts...)
    65  }
    66  
    67  // CreateOne executes a createSearchIndexes command to create a search index on the collection and returns the name of the new
    68  // search index. See the SearchIndexView.CreateMany documentation for more information and an example.
    69  func (siv SearchIndexView) CreateOne(
    70  	ctx context.Context,
    71  	model SearchIndexModel,
    72  	opts ...*options.CreateSearchIndexesOptions,
    73  ) (string, error) {
    74  	names, err := siv.CreateMany(ctx, []SearchIndexModel{model}, opts...)
    75  	if err != nil {
    76  		return "", err
    77  	}
    78  
    79  	return names[0], nil
    80  }
    81  
    82  // CreateMany executes a createSearchIndexes command to create multiple search indexes on the collection and returns
    83  // the names of the new search indexes.
    84  //
    85  // For each SearchIndexModel in the models parameter, the index name can be specified.
    86  //
    87  // The opts parameter can be used to specify options for this operation (see the options.CreateSearchIndexesOptions
    88  // documentation).
    89  func (siv SearchIndexView) CreateMany(
    90  	ctx context.Context,
    91  	models []SearchIndexModel,
    92  	_ ...*options.CreateSearchIndexesOptions,
    93  ) ([]string, error) {
    94  	var indexes bsoncore.Document
    95  	aidx, indexes := bsoncore.AppendArrayStart(indexes)
    96  
    97  	for i, model := range models {
    98  		if model.Definition == nil {
    99  			return nil, fmt.Errorf("search index model definition cannot be nil")
   100  		}
   101  
   102  		definition, err := marshal(model.Definition, siv.coll.bsonOpts, siv.coll.registry)
   103  		if err != nil {
   104  			return nil, err
   105  		}
   106  
   107  		var iidx int32
   108  		iidx, indexes = bsoncore.AppendDocumentElementStart(indexes, strconv.Itoa(i))
   109  		if model.Options != nil && model.Options.Name != nil {
   110  			indexes = bsoncore.AppendStringElement(indexes, "name", *model.Options.Name)
   111  		}
   112  		indexes = bsoncore.AppendDocumentElement(indexes, "definition", definition)
   113  
   114  		indexes, err = bsoncore.AppendDocumentEnd(indexes, iidx)
   115  		if err != nil {
   116  			return nil, err
   117  		}
   118  	}
   119  
   120  	indexes, err := bsoncore.AppendArrayEnd(indexes, aidx)
   121  	if err != nil {
   122  		return nil, err
   123  	}
   124  
   125  	sess := sessionFromContext(ctx)
   126  
   127  	if sess == nil && siv.coll.client.sessionPool != nil {
   128  		sess = session.NewImplicitClientSession(siv.coll.client.sessionPool, siv.coll.client.id)
   129  		defer sess.EndSession()
   130  	}
   131  
   132  	err = siv.coll.client.validSession(sess)
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  
   137  	wc := siv.coll.writeConcern
   138  	if sess.TransactionRunning() {
   139  		wc = nil
   140  	}
   141  	if !writeconcern.AckWrite(wc) {
   142  		sess = nil
   143  	}
   144  
   145  	selector := makePinnedSelector(sess, siv.coll.writeSelector)
   146  
   147  	op := operation.NewCreateSearchIndexes(indexes).
   148  		Session(sess).WriteConcern(wc).ClusterClock(siv.coll.client.clock).
   149  		Database(siv.coll.db.name).Collection(siv.coll.name).CommandMonitor(siv.coll.client.monitor).
   150  		Deployment(siv.coll.client.deployment).ServerSelector(selector).ServerAPI(siv.coll.client.serverAPI).
   151  		Timeout(siv.coll.client.timeout)
   152  
   153  	err = op.Execute(ctx)
   154  	if err != nil {
   155  		_, err = processWriteError(err)
   156  		return nil, err
   157  	}
   158  
   159  	indexesCreated := op.Result().IndexesCreated
   160  	names := make([]string, 0, len(indexesCreated))
   161  	for _, index := range indexesCreated {
   162  		names = append(names, index.Name)
   163  	}
   164  
   165  	return names, nil
   166  }
   167  
   168  // DropOne executes a dropSearchIndexes operation to drop a search index on the collection.
   169  //
   170  // The name parameter should be the name of the search index to drop. If the name is "*", ErrMultipleIndexDrop will be returned
   171  // without running the command because doing so would drop all search indexes.
   172  //
   173  // The opts parameter can be used to specify options for this operation (see the options.DropSearchIndexOptions
   174  // documentation).
   175  func (siv SearchIndexView) DropOne(
   176  	ctx context.Context,
   177  	name string,
   178  	_ ...*options.DropSearchIndexOptions,
   179  ) error {
   180  	if name == "*" {
   181  		return ErrMultipleIndexDrop
   182  	}
   183  
   184  	if ctx == nil {
   185  		ctx = context.Background()
   186  	}
   187  
   188  	sess := sessionFromContext(ctx)
   189  	if sess == nil && siv.coll.client.sessionPool != nil {
   190  		sess = session.NewImplicitClientSession(siv.coll.client.sessionPool, siv.coll.client.id)
   191  		defer sess.EndSession()
   192  	}
   193  
   194  	err := siv.coll.client.validSession(sess)
   195  	if err != nil {
   196  		return err
   197  	}
   198  
   199  	wc := siv.coll.writeConcern
   200  	if sess.TransactionRunning() {
   201  		wc = nil
   202  	}
   203  	if !writeconcern.AckWrite(wc) {
   204  		sess = nil
   205  	}
   206  
   207  	selector := makePinnedSelector(sess, siv.coll.writeSelector)
   208  
   209  	op := operation.NewDropSearchIndex(name).
   210  		Session(sess).WriteConcern(wc).CommandMonitor(siv.coll.client.monitor).
   211  		ServerSelector(selector).ClusterClock(siv.coll.client.clock).
   212  		Database(siv.coll.db.name).Collection(siv.coll.name).
   213  		Deployment(siv.coll.client.deployment).ServerAPI(siv.coll.client.serverAPI).
   214  		Timeout(siv.coll.client.timeout)
   215  
   216  	err = op.Execute(ctx)
   217  	if de, ok := err.(driver.Error); ok && de.NamespaceNotFound() {
   218  		return nil
   219  	}
   220  	return err
   221  }
   222  
   223  // UpdateOne executes a updateSearchIndex operation to update a search index on the collection.
   224  //
   225  // The name parameter should be the name of the search index to update.
   226  //
   227  // The definition parameter is a document describing the definition for the search index. It cannot be nil.
   228  //
   229  // The opts parameter can be used to specify options for this operation (see the options.UpdateSearchIndexOptions
   230  // documentation).
   231  func (siv SearchIndexView) UpdateOne(
   232  	ctx context.Context,
   233  	name string,
   234  	definition interface{},
   235  	_ ...*options.UpdateSearchIndexOptions,
   236  ) error {
   237  	if definition == nil {
   238  		return fmt.Errorf("search index definition cannot be nil")
   239  	}
   240  
   241  	indexDefinition, err := marshal(definition, siv.coll.bsonOpts, siv.coll.registry)
   242  	if err != nil {
   243  		return err
   244  	}
   245  
   246  	if ctx == nil {
   247  		ctx = context.Background()
   248  	}
   249  
   250  	sess := sessionFromContext(ctx)
   251  	if sess == nil && siv.coll.client.sessionPool != nil {
   252  		sess = session.NewImplicitClientSession(siv.coll.client.sessionPool, siv.coll.client.id)
   253  		defer sess.EndSession()
   254  	}
   255  
   256  	err = siv.coll.client.validSession(sess)
   257  	if err != nil {
   258  		return err
   259  	}
   260  
   261  	wc := siv.coll.writeConcern
   262  	if sess.TransactionRunning() {
   263  		wc = nil
   264  	}
   265  	if !writeconcern.AckWrite(wc) {
   266  		sess = nil
   267  	}
   268  
   269  	selector := makePinnedSelector(sess, siv.coll.writeSelector)
   270  
   271  	op := operation.NewUpdateSearchIndex(name, indexDefinition).
   272  		Session(sess).WriteConcern(wc).CommandMonitor(siv.coll.client.monitor).
   273  		ServerSelector(selector).ClusterClock(siv.coll.client.clock).
   274  		Database(siv.coll.db.name).Collection(siv.coll.name).
   275  		Deployment(siv.coll.client.deployment).ServerAPI(siv.coll.client.serverAPI).
   276  		Timeout(siv.coll.client.timeout)
   277  
   278  	return op.Execute(ctx)
   279  }
   280  

View as plain text