How to group in mongo from ruby - ruby

I'm trying to group by 2 fields in my mongo collection from ruby. I've got it working from within the mongo client however can't get the ruby syntax right.
My command on the mongo client is
db.truckroutes.group({key: { "route" : 0, "assetId" : "" }, reduce: function (curr, result) {}, initial: {} })
Could anyone give me any ideas what the ruby syntax would be like to perform this command?
Thank you in advance!

OK, managed to fix this after spending a while experimenting.
trucks = #mongoCollection.group( ["route", "assetId"], { }, { }, "function() {}")

Related

How to combine Aggregate function with update

I could not find a way to translate the fowling MongoDb command into C#
db.Queue.aggregate(
[
{ $match: { "Processed": false } },
{ $sort: { "LastTimeChanged": 1  } },
{ $limit: 1 },
{ $set: { "WorkerName": "WORKER_NAME", "Processed": true }  },
{ "$merge": "Queue"  }])
The issues that I fund was with the $set and $merge command
$set -> in the MongoDb.Driver for .NET, associated with the Aggregate command I could not find any command that look like the $set
$merge -> the merge command examples are exclusive for merging collections and in this case, I could not find a way to use the Merge method in the API.
Any one can throw light here!??
thanks
Paulo Aboim Pinto
I found a way to execute the command using the MongoDb.Driver but I thing there should be a better and fluent way of doing it
var filter = Builders<QueueCollection>.Filter.And
(
Builders<QueueCollection>.Filter.Eq(x => x.WorkerName, string.Empty),
Builders<QueueCollection>.Filter.Eq(x => x.Processed, false)
);
var sortOptions = Builders<QueueCollection>
.Sort.Ascending("LastTimeChanged");
this.queueCollection.Aggregate()
.Match(filter)
.Sort(sortOptions)
.Limit(1)
.AppendStage<QueueCollection>("{ $set: { 'WorkerName': 'WORKER_NAME' } }")
.AppendStage<QueueCollection>("{ $merge: 'Queue' }")
.ToList();
This works for now, but I would like to want still to know:
How do I replace the $set in the Aggregate pipeline
How do I write a proper $merge command.
thanks in advance for any answer
Paulo Aboim Pinto

How can I sort a request to a view - using nodejs API

I'm querying a cloudant DB from my nodejs App.
I am now trying to sort results from a view query.
My index (keys) are like this:
[ "FR000001", 1577189089166 ]
[ "FR000001", 1577189089165 ]
etc
from the following view:
function(doc) {
emit([doc.siteId, doc.creationDate],{"id" :doc._id, "rev": doc._rev, "siteId": doc.siteId, "creationDate": doc.creationDate, "scores": doc.scores, locationId: doc.locationId});
}
I managed to make that work on a real index using the syntax "sort: "-creationDate" " using syntax found in the bugs sections of cloudant github.
var ddoc = {
q: "site:\"" + id + "\"",
include_docs: false,
sort: "-creationDate",
};
const tmp = await cloudant.use('alarms').search('alarmSearch', 'IndexBySite', ddoc);
I can't make it work on my view with an array of query parameters. I have tried different variation around:
var ddoc_view = {
startkey: ["siteid1",0000000000000],
endkey: ["siteid1",9999999999999],
include_docs: true,
sort: "creationDate"
};
Can anyone help finding the right syntax, or pointing me to where I can find good "cloudant API for nodejs" documentation? for instance there is nothing on how to use sort" on the github... Thanks...
ok after another day of searching:
- best documentation I found is directly the couchdb doc: https://docs.couchdb.org/en/stable/ddocs/views/intro.html
- I ended up modifying the view:
emit([doc.creationDate, doc.siteId], {"id" :doc._id, "rev": doc._rev, "siteId": doc.siteId, "locationTag":doc.locationTag});
and the request:
var ddoc_view = {
endkey: [0000000000000, siteid],
startkey: [9999999999999, siteid],
include_docs: false,
descending: true,
limit: docsReturned,
};
To get a sorted response.

Ruby finding duplicates in MongoDB

I am struggling to get this working efficiently I think map reduce is the answer but can't getting anything working, I know it is probably a simple answer hopefully someone can help
Entry Model looks like this:
field :var_name, type: String
field :var_data, type: String
field :var_date, type: DateTime
field :external_id, type: Integer
If the external data source malfunctions we get duplicate data. One way to stop this was when consuming the results we check if a record with the same external_id already exists, as one we have already consumed. However this is slowing down the process a lot. The plan now is to check for duplicates once a day. So we are looking get a list of Entries with the same external_id. Which we can then sort and delete those no longer needed.
I have tried adapting the snippet from here https://coderwall.com/p/96dp8g/find-duplicate-documents-in-mongoid-with-map-reduce as shown below but get
failed with error 0: "exception: assertion src/mongo/db/commands/mr.cpp:480"
def find_duplicates
map = %Q{
function() {
emit(this.external_id, 1);
}
}
reduce = %Q{
function(key, values) {
return Array.sum(values);
}
}
Entry.all.map_reduce(map, reduce).out(inline: true).each do |entry|
puts entry["_id"] if entry["value"] != 1
end
end
Am I way off? Could anyone suggest a solution? I am using Mongiod, Rails 4.1.6 and Ruby 2.1
I got it working using the suggestion in the comments of the question by Stennie using the Aggregation framework. It looks like this:
results = Entry.collection.aggregate([
{ "$group" => {
_id: { "external_id" => "$external_id"},
recordIds: {"$addToSet" => "$_id" },
count: { "$sum" => 1 }
}},
{ "$match" => {
count: { "$gt" => 1 }
}}
])
I then loop through the results and delete any unnecessary entries.

Rails4 + Json API : Increase detail of response

I'm a newbie on RoR (and Ruby). I need a little help about a json response (with Grape).
This is the sample:
{
events: [
{
'some data':'some data',
place_id: 1
}
]
}
Now this is the result of Events.all in Rails, but I want to make for each event a query for the place, to have more data instead only id. I'm sure that new lambda function can help me, but for now I have no idea about to make it. I'm trying without success...
Thanks in advance
UPDATE
Desired result
{
events: [
{
'some data':'some data',
place : {
id: 1,
name: 'Blablabla'
}
]
}
Consider using ActiveModelSerializers which allows you to define how your models should be serialized in a manner similar to ActiveRecord DSL (e.g. your problem would be solved by defining that event has_one :place)
:events => events.as_json(include: :place)
This is a useful for my problem. After add belongs_to, obviously.
from http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html

MongoDB Group using Ruby driver

I'm trying to bring back a list of year/month combinations with counts for describing blog posts. The idea is that they will be displayed like so:
January 2010 (1 post)
December 2009 (2 posts)
...
I have managed to get this to work using the MongoDB JS shell, and it returns results in a useful format:
db.posts.group({
keyf: function(x){
return {
month: x.datetime.getMonth(),
year:x.datetime.getFullYear()
};
},
reduce: function(x,y){ y.count++ },
initial:{count:0}
})
Results:
[ { "month" : 0, "year" : 2010, "count" : 3 },
{ "month" : 0, "year" : 1970, "count" : 1 } ]
This is great, exactly what I'm after. However, trying to convert this into code appropriate for the ruby driver, I can't get it to work. I have looked at the documentation and from my understanding, the following should yield the same results (I'm using MongoMapper, hence the Post.collection):
#archive = Post.collection.group(
"function(x) { return { month: x.datetime.getMonth(), year:x.datetime.getFullYear() }; }",
nil, { :count => 0 }, 'function(x,y){y.count++}', true)
Instead of giving back the nice array of useful data, I'm getting this mess:
{
"function(x) { return { month: x.datetime.getMonth(), year:x.datetime.getFullYear() }; }" => nil,
"count" => 4.0
}
It seems that either it is completely defying its own documentation (and my understanding of the source code!) or I am missing something fundamental here. I'm almost pulling my hair out, any help gratefully accepted.
That's pretty strange behavior. I just ran your code locally, and everything worked. Can you verify that you're using the driver version 0.18.2? If so, make sure that that's the only version installed (just as a sanity check).
I don't think it should make any difference, but I wasn't running #group from MongoMapper -- I was using the gem alone. You might try that, too. Here's the code I ran:
require 'rubygems'
require 'mongo'
d = Mongo::Connection.new.db('blog')
c = d['post']
p c.group("function(x) { return { month: x.date.getMonth(), year:x.date.getFullYear() }; }",
nil,
{ :count => 0 },
"function(x,y){y.count++}",
true)

Resources