How to find result with mongo-driver by objectid field - mongodb

I have 2 structs:
type Customer struct {
MyID int `bson:"myID"`
}
type Bag struct {
Customer primitive.ObjectID `bson:"customer"`
}
But I dunno how to make filter to find document in Bag collection by Customer.MyID
I tried something like this:
filter := bson.D{{"customer", bson.D{{"myID", 123456789}}}}
cur, err := collection.Find(context.TODO(), filter)
Also tried this:
filter := bson.D{{"customer.myID", bson.D{{"$eq", 123456789}}}}
cur, err := collection.Find(context.TODO(), filter)
And I always get nothing in my cur variable. Please help me how to use it right.

The collection name must not appear in the filter, the collection on which you call Find() already represents (or should) the customer collection, so just use:
collection := client.Database("yourdatabase").Collection("customer")
filter := bson.M{
"myID": 123456789,
}
cur, err := collection.Find(context.TODO(), filter)
Or with bson.D:
filter := bson.D{{"myID", 123456789}}

Related

How to update many by objectid in mongodb using go driver

I want to bulk update collection by slice of objectid
Here is the function for updatemany
func BulkDeleteEmailContentFieldByIds(ids []primitive.ObjectID) error {
filter := bson.M{"_id": bson.M{"$in": ids}}
update := bson.D{{"$unset", bson.D{{"email_content", 1}}}}
result, err := collection.UpdateMany(ctx, filter, update)
if err != nil {
return err
}
pp.Printf("Bulk delete removed %v document(s)\n", result.ModifiedCount)
return nil
}
var trackingLogIds []primitive.ObjectID
for _, v := range userDocs {
wg.Add(1)
go func(v bson.M) {
defer wg.Done()
// do something to return objectID
trackingLogIds = append(trackingLogIds, emaDoc["_id"].(primitive.ObjectID))
}(v)
}
emadb.BulkDeleteEmailContentFieldByIds(trackingLogIds)
Is the slice trackingLogIds is the correct way to search for documents with objectId
And is the query for updatemany i doing is right?
If not then how can i improve it.
Thanks
I had test the function i provided and its working as expected.
Find all document in slice of objectid and unset the field email_content

How to replace a document in MongoDB with Go driver?

I'm trying to update a document in MongoDB with mongodb/mongo-go-driver. From its doc, one document can be replaced with:
var coll *mongo.Collection
var id primitive.ObjectID
// find the document for which the _id field matches id and add a field called "location"
// specify the Upsert option to insert a new document if a document matching the filter isn't found
opts := options.Replace().SetUpsert(true)
filter := bson.D{{"_id", id}}
replacement := bson.D{{"location", "NYC"}}
result, err := coll.ReplaceOne(context.TODO(), filter, replacement, opts)
if err != nil {
log.Fatal(err)
}
if result.MatchedCount != 0 {
fmt.Println("matched and replaced an existing document")
return
}
if result.UpsertedCount != 0 {
fmt.Printf("inserted a new document with ID %v\n", result.UpsertedID)
}
But what if I have fields more than like 20. I am wondering if I can update without re-writing all fields again, I tried something like this:
// Replacement struct
type Input struct {
Name *string `json:"name,omitempty" bson:"name,omitempty" validate:"required"`
Description *string `json:"description,omitempty" bson:"description,omitempty"`
Location *string `json:"location,omitempty" bson:"location,omitempty"`
}
...
oid, _ := primitive.ObjectIDFromHex(id) // because 'id' from request is string
filter := bson.M{"_id", oid} // throws `[compiler] [E] missing key in map literal`
// ^^^
replacement := bson.D{{"$set", input}} // throws `composite literal uses unkeyed fields`
// ^^^^^
result, err := coll.ReplaceOne(context.TODO(), filter, replacement, opts)
...
But it throws errors at filter and replacement. How can I replace a whole document properly?
bson.M is a map, so if you use it, you have to write: bson.M{"_id": oid}. See missing type in composite literal go AND missing key in map literal go.
And bson.D is a slice of structs, so if you use it, you should write bson.D{{Key:"$set", Value: input}}. Omitting the field names is not a compiler error, it's just a go vet warning.
Now on to replacing. The replacement must be a document itself, without using $set (this is not updating but replacing). For reference see MongoDB's collection.replaceOne() and the driver's doc: Collection.ReplaceOne():
The replacement parameter must be a document that will be used to replace the selected document. It cannot be nil and cannot contain any update operators (https://docs.mongodb.com/manual/reference/operator/update/).
So do it like this:
filter := bson.M{"_id": oid}
result, err := coll.ReplaceOne(context.TODO(), filter, input, opts)
Here is the complete code. This will help readers to understand the code flow.
func UpdateFunction(echoCtx echo.Context) (error) {
//Web Section
documentID := echoCtx.Param("id") //Provided in URL
var newObject myStruct
err := echoCtx.Bind(&newObject) // Json with updated values sent by web client mapped to struct
ctx := echoCtx.Request().Context()
//Database Section
database := db.Conn.Database("myDatabase")
collection := database.Collection("myCollection")
existingHexID, err := primitive.ObjectIDFromHex(documentID)
if err != nil {
fmt.Println("ObjectIDFromHex ERROR", err)
} else {
fmt.Println("ObjectIDFromHex:", existingHexID)
}
// Replacing OLD document with new using _id
filter := bson.M{"_id": newDocumentID}
result, err := collection.ReplaceOne(ctx, filter, newObject)
if err != nil {
log.Fatal(err)
}
fmt.Printf(
"insert: %d, updated: %d, deleted: %d /n",
result.MatchedCount,
result.ModifiedCount,
result.UpsertedCount,
)
return echoCtx.JSON(http.StatusOK, result.ModifiedCount)
}

Why does my mongodb query return 0 results?

This is my database collection:
With this go code, I try to get all the users who are either involved in the story or created the story with the given id.
func main() {
for stf.DB == nil {
}
collection := stf.DB.Collection("user")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
id, _ := primitive.ObjectIDFromHex("5cb4dd7e29d3dca573a73d4c")
fter := bson.M{"_id": id}
involvedFilter := bson.M{"stories_involved": fter}
createdFilter := bson.M{"stories_created": fter}
filter := bson.M{"$or": []bson.M{involvedFilter, createdFilter}}
cur, err := collection.Find(ctx, filter)
if err != nil {
log.Fatal(err.Error())
}
defer cur.Close(ctx)
for cur.Next(ctx) {
var result bson.M
err := cur.Decode(&result)
if err != nil {
log.Fatal(err.Error())
}
fmt.Println(result)
}
if err := cur.Err(); err != nil {
log.Fatal(err.Error())
}
}
The code doesn't output any errors, but it also doesn't output any objects...
Thanks for your help in advance!
Your query translates into:
{"$or":[
{"stories_involved":{
"_id": ObjectId("5cb4dd7e29d3dca573a73d4c")}},
{"stories_created":{
"_id":ObjectId("5cb4dd7e29d3dca573a73d4c")}}
]}
Which means that it's searching for either a document with a nested document
i.e:
{stories_involved: {_id: <value>}} OR {stories_created: {_id: <value>}}.
However, the documents in the collection contains nested document array i.e:
{stories_involved: [{_id:<value>}]} OR {stories_created: [{_id:<value>}]}
This is the reason your query is not returning any value (and no error because the query syntax is correct).
There are two ways of Querying a document nested in an array using dot notation. If you know the index of the array for the document, you can just specify the position:
id, _ := primitive.ObjectIDFromHex("5cb4dd7e29d3dca573a73d4c")
involvedFilter := bson.M{"stories_involved.0._id": id}
createdFilter := bson.M{"stories_created.0._id": id}
filter := bson.M{"$or": []bson.M{involvedFilter, createdFilter}}
cur, err := collection.Find(ctx, filter)
If you do not know the index position of the document nested in the array, concatenate the name of the array field, with a dot (.) and the name of the field in the nested document:
id, _ := primitive.ObjectIDFromHex("5cb4dd7e29d3dca573a73d4c")
involvedFilter := bson.M{"stories_involved._id": id}
createdFilter := bson.M{"stories_created._id": id}
filter := bson.M{"$or": []bson.M{involvedFilter, createdFilter}}
cur, err := collection.Find(ctx, filter)
See also MongoDB: Query Documents

mongo-go-driver find a document by _id

I'm trying to find a document by its auto generated _id field. Code below returns nothing:
var documentID bson.RawValue
documentID.Type = 7
documentID.Value = []byte("5c7452c7aeb4c97e0cdb75bf")
objID := documentID.ObjectID()
value := collection.FindOne(ctx, bson.M{"_id": objID})
The value I provided is a real document id I got from Mongo Express
"_id": ObjectID("5c7452c7aeb4c97e0cdb75bf")
In case you're wondering why I bother with RawValue, I found examples using bson.EC.ObjectID but bson package doesn't seem to have EC type, also I found some examples mentioning github.com/mongodb/mongo-go-driver/bson/objectid package, but I could not find that package either. I previously developed with mgo but I'm new to mongo-go-driver, so if you can point an easy way to declare an ObjectID.
As #Carlos mentioned, I changed my code as this and everything works well.
objID, _ := primitive.ObjectIDFromHex("5c7452c7aeb4c97e0cdb75bf")
value := collection.FindOne(ctx, bson.M{"_id": objID})
You can use some thing like this:
var userDB user
objectIDS, _ := primitive.ObjectIDFromHex(userID)
collectionUser := dBClient.Database("MyDatabase").Collection("Users")
filter := bson.M{"_id": objectIDS}
err := collectionUser.FindOne(ctx, filter).Decode(&userDB)
if err != nil {
fmt.Println("errror retrieving user userid : " + userID)
}
package main
import (
"fmt"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"context"
)
// get collection "users" from db() which returns *mongo.Client
var userCollection = db().Database("goTest").Collection("users")
func mongodriver_find_by_id() {
objectId, err1 := primitive.ObjectIDFromHex("6041c3a6cfcba2fb9c4a4fd2")
if err1 != nil {fmt.Println(err1)}
findone_result := userCollection.FindOne(context.TODO(), bson.M{"_id":objectId})
var bson_obj bson.M
if err2 := findone_result.Decode(&bson_obj); err2 != nil {fmt.Println(err2)}
fmt.Println("bson_obj:", bson_obj)
}

Sequential queries with golang & mongodb

Wondering what is best way to make sequential queries from Golang for a mongodb.
Example lets say you have :
result *bson.M
ids:=["543d171c5b2c12420dd016","543d171c5b2dd016"]
oids := make([]bson.ObjectId, len(ids))
for i := range ids {
oids[i] = bson.ObjectIdHex(ids[i])
}
query := bson.M{"_id": bson.M{"$in": oids}}
error:= c.Find(query).All(&result)
And you want to take the output of the _ids and use it as a query for another table.
So is this correct?
query = bson.M{"_id": bson.M{"$in": result}}
Here's how to construct a query using the ids of documents returned from some other query.
var docs []bson.M
if err := c.Find(query).All(&docs); err != nil {
// handle error
}
docIDs := make([]interface{}, len(docs))
for i := range docs {
docIds[i] = docs[i]["_id"]
}
query = bson.M{"_id": bson.M{"$in": docIDs}}