How do we create timeseries collections with mongodb golang driver? - mongodb

I am trying to create timeseries collections => https://www.mongodb.com/developer/how-to/new-time-series-collections/#expireafterseconds with the following function
As you can see below i have tried different iterations to pass options to the CreateCollection() but nothing works. Searched for hours for an example of this and could not find any, and one would think will be easy to setup based on current documentation but hours later and here to get help
func CollectionsTimeSeries(name string) {
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
// options := {
// "TimeSeriesOptions": {
// "TimeField": "time_stamp",
// "MetaField": "stock",
// "Granularity": "minutes",
// },
// "ExpireAfterSeconds": 2592000,
// }
// options := {
// timeseries: {
// timeField: "time_stamp",
// metaField: "stock",
// granularity: "minutes",
// },
// expireAfterSeconds: 2592000
// }
options := {
"timeseries": {
"timeField": "time_stamp",
"metaField": "stock",
"granularity": "minutes",
},
"expireAfterSeconds": 2592000
}
// database.GetConnection.CreateCollection(ctx, name, {
// timeseries: {
// timeField: "time_stamp",
// metaField: "stock",
// granularity: "minutes",
// },
// expireAfterSeconds: 2592000
// })
database.GetConnection.CreateCollection(ctx, name, options)
}
Get the following errors
syntax error: unexpected {, expecting expression
syntax error: unexpected }, expecting comma or )

Use the options package to create an options instance containing time series options:
opt:=options.CreateCollection().
SetTimeseriesOptions(options.TimeSeries().
SetGranularity("...").
SetMetaField("...").
SetTimeField("..."))

Related

bson.M filter for db.collection.find( {}, {your_key:1, _id:0})

I want to get the entire list_atttributes field from my mongo document:
db.config.find({},{list_attributes:1, _id:0});
[
{
list_attributes: {
'0': { field: 'LASTNAME', field_key: 'lastname', dataType: 'text' },
'1': { field: 'FIRSTNAME', field_key: 'firstname', dataType: 'text' },
'2': { field: 'SMS', dataType: 'text' },
'3': {
field: 'DOUBLE_OPT-IN',
dataType: 'category',
order: 1,
catAttrib: { '1': 'Yes', '2': 'No' }
},
'4': { field: 'OPT_IN', dataType: 'boolean', order: 2 },
'5': { field: 'TEST_NUMBER', dataType: 'float', order: 3 },
'6': { field: 'TEST_DATE', dataType: 'date', order: 4 }
}
}
]
I tried to write it like this:
filter := options.Find().SetProjection(bson.M{"list_attributes": 1})
// Pass the filter to Find() to return a MongoDB cursor
cursor, err := col.Find(ctx, filter)
if err != nil {
log.Fatal("col.Find ERROR:", err)
}
But the cursor returns 0 results here.
How do I create a bson.M filter for the same projection?
I am using the official mongodb drive for go.
Something like this should work
import (
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func find(ctx context.Context) error {
// ...
cursor, err := collection.Find(ctx, bson.M{}, options.Find().SetProjection(bson.M{"list_attributes": 1}))
if err != nil {
return err
}
// ...
return nil
}

Mongodb aggregate cursor not returning array from lookup result - Golang

I have two MongoDB collections, one users and another for accesskeys. I want to get an aggregation of the users together with their accesskeys depending on whether they are subscribed to a specific channel or not. However when I run the code, the cursor data has the user data but the variable containing the lookup array is missing. The pipeline syntax is however working fine on mongodb-compass.
Data
Users Collection Sample
id: 42069
displayName: "tiredApe"
subscribedChannel: "BananaClips"
AccessKeys Collection Sample
userId: 42069"
apiKey: "yadayadayada"
Code
pipeline := `[
{
'$match': {
'subscribedChannel': 'BananaClips'
}
},
{
'$lookup': {
'from': 'accesskeys',
'let': {
'searchId': {
'$toString': '$id'
}
},
'pipeline': [
{
'$match': {
'$expr': {
'$eq': [
'$userId', '$$searchId'
]
}
}
}
],
'as': 'accesskeys'
}
},
{
'$unwind': {
'path': '$accesskeys'
}
}
]`
var err error
var cur *mongo.Cursor
var doc bson.M
opts := options.Aggregate()
opts.SetAllowDiskUse(true)
opts.SetBatchSize(15)
if cur, err = userCollection.Aggregate(ctx, MongoPipeline(pipeline), opts); err != nil {
panic(err)
}
defer cur.Close(ctx)
for cur.Next(ctx) {
fmt.Println(cur.Current.String())
}
Helper function to convert the Pipeline string to a mongo.Pipeline object :
func MongoPipeline(str string) mongo.Pipeline {
var pipeline = []bson.D{}
str = strings.TrimSpace(str)
if strings.Index(str, "[") != 0 {
var doc bson.D
bson.UnmarshalExtJSON([]byte(str), false, &doc)
pipeline = append(pipeline, doc)
} else {
bson.UnmarshalExtJSON([]byte(str), false, &pipeline)
}
return pipeline
}
The expected result (as evidenced from the many trial on mongodb-compass) :
{
id: 42069,
displayName: "tiredApe",
subscribedChannel: "BananaClips",
accesskeys: {
userId: 42069,
apiKey: "yadayadayada"
}
}
The current result from Golang :
{
id: 42069,
displayName: "tiredApe",
subscribedChannel: "BananaClips"
}
Really looking for a breakthrough. Been stuck at it for half a day and can't figure out what I am missing or why the accesskey variable is missing from the result. Thanks in advance.

Mongoose: Update nested document

I have following JSON structure,
{
"projectId": "service-request-service",
"projectVersion": [{
"version":"1",
"localConfig": [{
"port": "3003",
"mongoURI": "mongodb://localhost:27017/serviceRequest",
"MQ": "RMQ",
"logLevel": "2",
"version": "1.1",
"created": "03-06-2018 03:11:00 PM",
"active": "N"
},
{
"port": "3004",
"mongoURI": "mongodb://localhost:27017/serviceRequest",
"MQ": "IMQ",
"logLevel": "1",
"version": "1.2",
"created": "07-06-2018 03:11:00 PM",
"active": "Y"
}]
}]
}
Now, I want to update all port and active values of localConfig. I tried using different ways,
using markModified
ProjectConfig.findOne({'projectId' : projectId,
'projectVersion.version' : version})
.exec(function(err,pc){
pc.projectVersion[0].localConfig[0].active = "N";
pc.projectVersion[0].localConfig[0].port = "5555";
pc.markModified('localConfig');
pc.save(function(err,result){
if (err) {
console.log(err);
}
console.log("## SUCCESSFULLY SAVED ");
});
});
Iterating using for loop.
ProjectConfig.findOne({'projectId' : projectId,
'projectVersion.version' : version}).exec(function(err,pc){
for(i = 0; i < pc.projectVersion.length ; i++){
for(j = 0; j < pc.projectVersion[i][envQuery].length ; j++){
pc.projectVersion[i][envQuery][j].active = 'N';
pc.projectVersion[i][envQuery][j].port = '5555';
}
}
pc.save(function (err, result) {
if (err) {
console.log(err);
}
console.log("## SUCCESSFULLY SAVED ");
});
});
Using arrayFilters,
let conditions = {};
let update = {$set: {"projectVersion.$[i].localConfig.$[].port": "5555"}};
let options = {arrayFilters:[{"i.version":"1"}]};
pc.update(conditions,update,options,function(err,result){
if (err) {
console.log(err);
}
console.log("## SUCCESSFULLY SAVED ");
});
But, I am getting below error.
MongooseError: Callback must be a function, got [object Object]
Please provide me the way to update document.
Current version of MongoDB : v3.6.6 & Mongoose : ^5.0.14
Using arrayFilters, I am not applying update method on scheme rather applying on object return by find method.
When I directly apply update method on schema, its working.
let conditions = { "projectId" : "32804-service-request-service" };
let update = { $set: {
"projectVersion.$[i].localConfig.$[j].port" : "5555",
}
};
let options = {arrayFilters:[{"i.version":"1" },{ "j.port" : "3003"}]};
ProjectConfig.update(conditions, update, options, function(err,result){
if (err) {
return res.status(500).json({
title: 'An error occurred',
error: err
});
}
res.status(200).json({
message: 'SUCCESS',
obj: result
});
});

Golang find a value from a map of nested json data from MongoDB

I am trying to receive data from my MongoDB using MGO in a map of type []map[string]interface{}
My JSON looks like this -
{
"_id":"string",
"brandId":123,
"category":{
"television":[
{
"cat":"T1",
"subCategory":[
{
"subCat":"T1A TV",
"warrantyPeriod":6
}
],
"warrantyPeriod":12
},
{
"cat":"T2",
"subCategory":[
{
"subCat":"T2A",
"warrantyPeriod":18
},
{
"subCat":"T2B",
"warrantyPeriod":9
}
],
"warrantyPeriod":15
},
{
"cat":"T3",
"subCategory":[
{
"subCat":"T3A",
"warrantyPeriod":3
},
{
"subCat":"T3B",
"warrantyPeriod":5
},
{
"subCat":"T3C",
"warrantyPeriod":7
},
{
"subCat":"T3D",
"warrantyPeriod":11
}
],
"warrantyPeriod":4
}
],
"television_warrantyPeriod":24
},
"title":"BrandName"
}
I would ideally pass in the category name i.e. 'television' and cat and subCat values which could be optional.
For e.g. something like this -
{
"categorySlug": "television",
"brandId": "123",
"model": "T2"
}
In which case I would expect to find '15' which is the warrantyPeriod value for T2 if there are no T2A or T2B specified.
My query functions look like this -
var data map[string]string
err := json.NewDecoder(r.Body).Decode(&data)
log.Println(err)
var buffer bytes.Buffer
buffer.WriteString("category.")
buffer.WriteString(data["categorySlug"])
brandId, _ := strconv.Atoi(data["brandId"])
concernedbrandandcategory := database.GetMappedFields("Brands", bson.M{"brandId": brandId, buffer.String(): bson.M{"$exists": true}}, bson.M{buffer.String(): 1})
categorymap := concernedbrandandcategory[0]
log.Println(categorymap["category"]["television"], reflect.TypeOf(categorymap))
My GetMappedFields function looks like this -
func GetMappedFields(collectionName string, query interface{}, selector interface{}) (result []map[string]interface{}) {
MgoSession.DB(Dbname).C(collectionName).Find(query).Select(selector).All(&result)
return
}
I'm just not able to wrap my head around this nested structure which sometimes returns a map and sometimes an interface!
Any help would be highly appreciated!
you can do something like this
majorCat := body["categorySlug"]
category := body["category"]
subCategory := body["subCategory"]
brandId, err := strconv.Atoi(body["brandId"])
if err != nil {
log.Println(err)
}
result := database.GetMappedFields("Brands", bson.M{"brandId": brandId}, bson.M{"category": 1, "_id": 0})
internalObj := result[0]["category"].(map[string]interface{})
finalValue := internalObj["television_warrantyPeriod"]
if category != "" {
for _, v := range internalObj[majorCat].([]interface{}) {
subObj := v.(map[string]interface{})
if subObj["cat"] == category {
finalValue = subObj["warrantyPeriod"]
if subCategory != "" {
minorObj := subObj["subCategory"].([]interface{})
for _, iter := range minorObj {
kevVal := iter.(map[string]interface{})
if kevVal["subCat"] == subCategory {
finalValue = kevVal["warrantyPeriod"]
}
}
}
}
}
}
Hopefully this will do dynamically or you can create a struct so that it can directly be decoded into that cheers

auto-increment using loopback.js and MongoDB

i want to increase mongodb document number automatically using loopback.
I made function in mongo
function getNextSequence(name) {
var ret = db.counters.findAndModify(
{
query: { _id: name },
update: { $inc: { seq: 1 } },
new: true
}
);
return ret.seq;
}
db.tweet.insert(
{
"_id" : getNextSequence("userid"),
"content": "test",
"date": "1",
"ownerUsername": "1",
"ownerId": "1"
}
)
It is working in mongo shell.
However when I insert using loopback.js browser (http://localhost:3000/explorer/), It is not working.
400 error(SytaxError) code is showing.
I can not use mongo function in loopback rest API ?
I think problem is quotes in this line getNextSequence("userid"),
Create a collection counters with properties value and collection
{
"name": "counters",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"type": "number",
"collection": "string"
},
"validations": [],
"relations": {},
"acls": [
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
],
"methods": []
}
Now supposing your auto-increment collection name tweets.
Insert this value to counters.
{
"value" : 0,
"collection" : "tweet"
}
Now common/models/tweet.js
tweet.observe('before save', function (ctx, next) {
var app = ctx.Model.app;
//Apply this hooks for save operation only..
if(ctx.isNewInstance){
//suppose my datasource name is mongodb
var mongoDb = app.dataSources.mongodb;
var mongoConnector = app.dataSources.mongodb.connector;
mongoConnector.collection("counters").findAndModify({collection: 'tweet'}, [['_id','asc']], {$inc: { value: 1 }}, {new: true}, function(err, sequence) {
if(err) {
throw err;
} else {
// Do what I need to do with new incremented value sequence.value
//Save the tweet id with autoincrement..
ctx.instance.id = sequence.value.value;
next();
} //else
});
} //ctx.isNewInstance
else{
next();
}
}); //Observe before save..
I would love to add 1 more point to Robins Answer,you can add upsert:true so that it automatically creates the document if it doesn't exist
tweet.observe('before save', function (ctx, next) {
var app = ctx.Model.app;
//Apply this hooks for save operation only..
if(ctx.isNewInstance){
//suppose my datasource name is mongodb
var mongoDb = app.dataSources.mongodb;
var mongoConnector = app.dataSources.mongodb.connector;
mongoConnector.collection("counters").findAndModify({collection: 'tweet'}, [['_id','asc']], {$inc: { value: 1 }}, {new: true,upsert:true}, function(err, sequence) {
if(err) {
throw err;
} else {
// Do what I need to do with new incremented value sequence.value
//Save the tweet id with autoincrement..
ctx.instance.id = sequence.value.value;
next();
} //else
});
} //ctx.isNewInstance
else{
next();
}
}); //Observe before save..
You can do something like in this example for loopback 4
let last_record = await this.testRepository.findOne({order: ['id DESC']});
if(last_record) invoice.id = last_record.id+1;
This will generate your model with the property:
#property({
type: 'number',
id: true,
default: 1,
generated: false
})
id: number;
Hopefully, this helps, please write me if there is any other code. Thanks
If you want to use MongoDB operators directly in loopback methods you need to enable the option "allowExtendedOperators", you can do so on a per model basis or at the data source level (will apply to all models using the data source).
datasources.json:
"MongoDs": {
"host": "127.0.0.1",
"port": 27017,
"url": "mongodb://localUser:MYPASSWORD!#127.0.0.1:27017/test-database",
"database": "test-database",
"password": "MYPASSWORD!",
"name": "MongoDs",
"user": "localUser",
"useNewUrlParser": true,
"connector": "mongodb",
"allowExtendedOperators": true
},