How to perform Find, Distinct & Sort all together using go mongo driver - mongodb

I have a command which is made using "labix.org/v2/mgo" library
err = getCollection.Find(bson.M{}).Sort("department").Distinct("department", &listedDepartment)
this is working fine. But now I'm moving to the official golang mongo-driver "go.mongodb.org/mongo-driver/mongo" and I want to run this command in that library but there is no direct function that I can use with Find then Sort then Distinct. How can I achieve this command using this mongo-driver. The variable listedDepartment is type of []string. Please suggest me know the solutions.

You may use Collection.Distinct() but it does not yet support sorting:
// Obtain collection:
c := client.Database("dbname").Collection("collname")
ctx := context.Background()
results, err := c.Distinct(ctx, "department", bson.M{})
It returns a value of type []interface{}. If you know it contains string values, you may use a loop and type assertions to obtain the string values like this:
listedDepartment = make([]string, len(results))
for i, v := range results {
listedDepartment[i] = v.(string)
}
And if you need it sorted, simply sort the slice:
sort.Strings(listedDepartment)

Related

How to create a Powerset of MSetList?

I am creating an MSetList P with elements of type String, and I would like to obtain the Powerset of P. I am not being able to figure it out.
Code below.
Thanks for your help :-)
Require Import
Coq.MSets.MSetList
Coq.Strings.String
Coq.Structures.OrdersEx.
Module set := Make OrdersEx.String_as_OT.
Definition P := set.add "A"%string (set.add "B"%string (set.add "C"%string (set.add "D"%string set.empty))).
Compute P.
Answer was provided on the Coq Discourse Forum by Yves Bertot
The construction of set shows that you are using the Make function
with a module as argument. If you type Print Make., you see that
this is a functor taking a module of type OrderedType as argument,
and it produces a module with many fields, among which t, eq,
eq_equiv, lt, lt_strorder, lt_compat, compare,
compare_spec, and eq_dec. If you type Print OrderedType., you
see that these field are the ones required to make an OrderedType.
So Make constructs all the fields that would be required to call Make
again, thus producing the powerset.
You can just type :
Module pset := Make set.
and you will simply obtain a structure of sets, whose elements are in
set.t. The following example was tested with coq 8.15.
Require Import
Coq.MSets.MSetList
Coq.Strings.String
Coq.Structures.OrdersEx.
Module set := Make OrdersEx.String_as_OT.
Module pset := Make set.
Definition set1 := set.add "A"%string set.empty.
Definition set2 := set.add "B"%string set.empty.
Definition set3 := set.add "C"%string set1.
Definition pset1 := pset.add set1 (pset.add set2 pset.empty).
Compute pset.mem set3 pset1.
Compute pset.mem set2 pset1.

Dynamically create Aggregate pipeline for mongo-go-driver

https://godoc.org/github.com/mongodb/mongo-go-driver
I am trying to create an Aggregate pipeline dynamically. For example, I want to read a slice of string containing the oceans. I tried breaking these apart to pieces, but I could not find any methods to append elements.
pipeline := bson.NewArray(
bson.VC.DocumentFromElements(
bson.EC.SubDocumentFromElements(
"$match",
bson.EC.SubDocumentFromElements("ocean",
bson.EC.ArrayFromElements("$in",
bson.VC.String("Pacific Ocean"),
//bson.VC.String("Indian Ocean"),
),
),
bson.EC.SubDocumentFromElements("callTypeName",
bson.EC.ArrayFromElements("$in",
bson.VC.String("Wookie"),
bson.VC.String("Unknown 13"),
),
),
),
),
)
cur, err := collection.Aggregate(context.Background(), pipeline)
I thought the question was pretty clear, not sure if the first commentor was actually reading the statement carefully.
What this person was asking was to dynamically insert data given a list of data into the pipeline.
I had the same issue on a vue app my team and I are working on. Using your provided data, here is the general template:
Given a slice of string of oceans
a := []string{"Pacific Ocean", "Indian Ocean"}
Make a slice of size 0 of type *bson.Value
b := make([]*bson.Value, 0)
Loop through the slice of oceans and append bson converted values to slice b
for _, v := range a {
b = append(b, bson.VC.String(v))
}
Then create key-value pair so that mongo can look for matches
c := bson.EC.ArrayFromElements("$in", b...)
Then pass c into the pipeline
pipeline := bson.NewArray(
bson.VC.DocumentFromElements(
bson.EC.SubDocumentFromElements(
"$match",
bson.EC.SubDocumentFromElements("ocean", c),
),
),
)
This should give you an idea on how to dynamically pipeline for callTypeNames

How to convert DOM::MATRIX to Function

A simple example of what I am doing is as follows:
s := t*0.2:
b := matrix([0.5,0.6,0.1]):
f := matrix([sin(s),cos(s),s]):
X := transpose(b)*(f);
plotfunc2d(X,t=-2*PI..2*PI);
The error is:
Error: Expecting an arithmetical expression or a function. Got a 'Dom::Matrix()' for attribute 'Function' in the 'Function2d' object.
so, I need to convert types from Dom::Matrix to Function. I have tried:
coerce(X,DOM_EXPR);
I know that simply, this works:
s := t*0.2:
x := 0.5*sin(s)+0.6*cos(s)+0.1*s;
plotfunc2d(x,t=-2*PI..2*PI);
Is there a way to convert these types?
While the variable X itself is a DOM::Matrix(), the single element it contains is an arithmetical expression, so you need to pass the element itself to the plot function:
plotfunc2d(X[1],t=-2*PI..2*PI);

How do I use the contents of an array as a variable name?

Currently I store the contents of an array into a variable, then set that variable up using two % and store a value. My current code looks like this:
Test := {asdf: "blah"}
Temp := Test["asdf"]
%Temp% := "boo"
; above line is be the same as blah := "boo", but blah came from a variable
msgbox %blah% ; outputs "boo"
I don't like having to use the Temp variable like this.
The following compiles but blah stays blank:
(Test["asdf"]) := "boo"
%Test%["asdf"] := "boo"
The following gives me a compile error:
%(Test["asdf"])% := "boo"
I have a vague idea that it should be possible but I just can't find the syntax for it. How do I directly use the array instead of having to put it in a temp variable?
Just figured it out.
The problem here is creating variables using dynamic data may cause invalid variable names to be created. All sorts of ways to screw up here (spaces, UTF-8 code, etc).
One safer way is to use Associative Arrays:
Output := Object()
Test := {asdf: "blah"}
Output[(Test["asdf"])] := "boo"
msgbox % Output["blah"]
There are less restrictions on keys than variable names.
globalWrapper(NameOfTheGlobalVar, LocalVar) {
global
%NameOfTheGlobalVar% := LocalVar
}
Test := {asdf: "blah"}
globalWrapper(Test["asdf"], "boo")
msgbox %blah% ; outputs "boo"

Golang md5 Sum() function

package main
import (
"crypto/md5"
"fmt"
)
func main() {
hash := md5.New()
b := []byte("test")
fmt.Printf("%x\n", hash.Sum(b))
hash.Write(b)
fmt.Printf("%x\n", hash.Sum(nil))
}
Output:
*md5.digest74657374d41d8cd98f00b204e9800998ecf8427e
098f6bcd4621d373cade4e832627b4f6
Could someone please explain to me why/how do I get different result for the two print ?
I'm building up on the already good answers. I'm not sure if Sum is actually the function you want. From the hash.Hash documentation:
// Sum appends the current hash to b and returns the resulting slice.
// It does not change the underlying hash state.
Sum(b []byte) []byte
This function has a dual use-case, which you seem to mix in an unfortunate way. The use-cases are:
Computing the hash of a single run
Chaining the output of several runs
In case you simply want to compute the hash of something, either use md5.Sum(data) or
digest := md5.New()
digest.Write(data)
hash := digest.Sum(nil)
This code will, according to the excerpt of the documentation above, append the checksum of data to nil, resulting in the checksum of data.
If you want to chain several blocks of hashes, the second use-case of hash.Sum, you can do it like this:
hashed := make([]byte, 0)
for hasData {
digest.Write(data)
hashed = digest.Sum(hashed)
}
This will append each iteration's hash to the already computed hashes. Probably not what you want.
So, now you should be able to see why your code is failing. If not, take this commented version of your code (On play):
hash := md5.New()
b := []byte("test")
fmt.Printf("%x\n", hash.Sum(b)) // gives 74657374<hash> (74657374 = "test")
fmt.Printf("%x\n", hash.Sum([]byte("AAA"))) // gives 414141<hash> (41 = 'A')
fmt.Printf("%x\n", hash.Sum(nil)) // gives <hash> as append(nil, hash) == hash
fmt.Printf("%x\n", hash.Sum(b)) // gives 74657374<hash> (74657374 = "test")
fmt.Printf("%x\n", hash.Sum([]byte("AAA"))) // gives 414141<hash> (41 = 'A')
hash.Write(b)
fmt.Printf("%x\n", hash.Sum(nil)) // gives a completely different hash since internal bytes changed due to Write()
You have 2 ways to actually get a md5.Sum of a byte slice :
func main() {
hash := md5.New()
b := []byte("test")
hash.Write(b)
fmt.Printf("way one : %x\n", hash.Sum(nil))
fmt.Printf("way two : %x\n", md5.Sum(b))
}
According to http://golang.org/src/pkg/crypto/md5/md5.go#L88, your hash.Sum(b) is like calling append(b, actual-hash-of-an-empty-md5-hash).
The definition of Sum :
func (d0 *digest) Sum(in []byte) []byte {
// Make a copy of d0 so that caller can keep writing and summing.
d := *d0
hash := d.checkSum()
return append(in, hash[:]...)
}
When you call Sum(nil) it returns d.checkSum() directly as a byte slice, however if you call Sum([]byte) it appends d.checkSum() to your input.
From the docs:
// Sum appends the current hash to b and returns the resulting slice.
// It does not change the underlying hash state.
Sum(b []byte) []byte
so "*74657374*d41d8cd98f00b204e9800998ecf8427e" is actually a hex representation of "test", plus the initial state of the hash.
fmt.Printf("%x", []byte{"test"})
will result in... "74657374"!
So basically hash.Sum(b) is not doing what you think it does. The second statement is the right hash.
I would like to tell you to the point:
why/how do I get different result for the two print ?
Ans:
hash := md5.New()
As you are creating a new instance of md5 hash once you call hash.Sum(b) it actually md5 hash for b as hash itself is empty, hence you got 74657374d41d8cd98f00b204e9800998ecf8427e as output.
Now in next statement hash.Write(b) you are writing b to the hash instance then calling hash.Sum(nil) it will calculate md5 for b that you just written and sum it to previous value i.e 74657374d41d8cd98f00b204e9800998ecf8427e
This is the reason you are getting these outputs.
For your reference look at the Sum API:
func (d0 *digest) Sum(in []byte) []byte {
85 // Make a copy of d0 so that caller can keep writing and summing.
86 d := *d0
87 hash := d.checkSum()
88 return append(in, hash[:]...)
89 }