Does Meteor have a distinct query for collections? - mongodb

I'd like to return distinct fields in my collection. I know these are the docs for mongo operators, but I'm not familiar enough with the query language to know if this is possible?
Meteor.publish("distinctCollection", function() {
return Collection.find({ ... }, fields: { "myField": 1 });
});

Collection.find({}).distinct('myField', true);
To use, put the following in [project]/client/lib/a.js:
LocalCollection.Cursor.prototype.distinct = function (key,random) {
var self = this;
if (self.db_objects === null)
self.db_objects = self._getRawObjects(true);
if (random)
self.db_objects = _.shuffle(self.db_objects);
if (self.reactive)
self._markAsReactive({ordered: true,
added: true,
removed: true,
changed: true,
moved: true});
var res = {};
_.each(self.db_objects,function(value){
if(!res[value[key]]){
res[value[key]] = value;
}
});
return _.values(res);
};

Related

MogoDB findAndModify return WriteResult

I do query with logic "insert if not exists". Can i return upsert result without additional queries ?
var u = Builders<Blog>.Update
.SetOnInsert(f => f.BlogId, blogId)
.SetOnInsert(f => f.VideoId, videoId)
-- other fields...
var blog = Blog.FindOneAndUpdate<Blog>(c => c.BlogId == blogId && c.VideoId == VideoId, u,
new FindOneAndUpdateOptions<Blog>{IsUpsert = true, ReturnDocument = ReturnDocument.After}
);
bool wasUpsert = ?
return wasUpsert;
Use the new: true option, see 4.0 release notes.
Milestone.findOneAndUpdate({
......
}, {
......
}, {upsert: true, 'new': true}, function(err, res) {
// err === null
// res === null
done(err, res);
});
I would do it like this:
var filter = Builders<MyCollectionModel>.Filter
.Eq(x => x.Id, ObjectId.Parse("5ecd93f739a1c716ab2c2d44"));
var update = Builders<MyCollectionModel>.Update.Set(x => x.Email, "john.smith#gmail.com");
var updateResult = await context.MyCollectionModel
.UpdateOneAsync(filter, update, new UpdateOptions {IsUpsert = true});
updateResult.Dump(); // LINQPad
Then if a document with that id exists but no change was made you will get:
if a document with that id exists and the email was changed you will get:
and finally, if the document did not exist and therefore it was added, UpsertedId will show its id.

Multiple method calls on Collection.observe() event in Meteorjs

I have a 1 cursor to calculate total number of voters. I have two methods where first counts the total number of voters in my favour, second method counts the total number of voters done voting.
LIB/collection.js
infavourcount = new Mongo.Collection('infavourcount');
votedone = new Mongo.Collection('votedone');
SERVER/publish.js [count voters in my favour]
function upsertInFavourCount() {
var yes = voters.find({favour: {$regex:"Y", $options: 'i'}}).count();
var maybe = voters.find({favour: {$regex:"M", $options: 'i'}}).count();
var no = total - (yes + maybe);
infavourcount.upsert('infavour',
{
yes: yes ,
maybe: maybe,
no:no
}
);
}
// null name means send to all clients
Meteor.publish(null,function() {
upsertInFavourCount();
return infavourcount.find();
});
SERVER/publish.js [count successful votings]
function upsertVoteDone() {
var done = voters.find({voted: {$regex:"Y", $options: 'i'}}).count();
votedone.upsert('votedone',
{
done: done
}
);
}
Meteor.publish(null,function() {
upsertVoteDone();
return votedone.find();
});
var cursor = voters.find();
cursor.observe({
changed: upsertVoteDone
});
CLIENT/template/home.js
Template.home.onCreated(function(){
Meteor.subscribe('voters');
Meteor.subscribe('infavourcount');
Meteor.subscribe('votedone');
});
Template.home.helpers({
yesvote : function() {
return infavourcount.findOne().yes;
},
maybevote : function() {
return infavourcount.findOne().maybe;
},
novote : function() {
return infavourcount.findOne().no;
},
votedone : function() {
return votedone.findOne().done;
}
});
My problem is how to call multiple upsert methods in one observe method of Meteor published collection.
I got my solution by the way. The answer to this is add an function on "changed" or "added" or "removed" event and call n number of upsert methods therein.
cursor.observe({
changed: function(id, fields){
upsertInFavourCount();
upsertVoteDone();
}
});

Error with count of docs where criteria applies to embedded array

I have a mongoDB collection called Assignments, which have multiple bids (embedded arrays). When one of those bids are set as accepted:true, they are considered an accepted_bid.
I want a function which returns all the docs (or a count of docs) that have one bid out of many (embedded arrays), which are owned by the logged in user.
The following does not work. I'm looking to have {{stats.count}} in the HTML file.
Template.dashboard.stats = function() {
return Assignments.find({completed:true}, {
transform: function(doc) {
if(doc.bids) {
var accepted_bid = _(doc.bids).findWhere({owner:Meteor.userId(),accepted:true});
doc.bid = accepted_bid;
}
return doc;
}
});
};
Im not sure if this would work but it returns a count:
Template.dashboard.helpers({
stats: function() {
var assignments = Assignments.find({
completed: true
}, {
transform: function(doc) {
if (doc.bids) {
var accepted_bid = _(doc.bids).findWhere({
owner: Meteor.userId(),
accepted: true
});
if(accepted_bid) doc.bid = accepted_bid;
}
return doc;
}
}).fetch();
return _(assignments).chain().pluck("bid").compact().value().length;
}
});
It can be used with {{stats}}

MeteorJS: Collection always returns count of 0

I have an app that has a collection called Cities.
Right now, all I am trying to do is to get the consoleto print the count of documents in the collection, but it only returns 0
Client.js
Meteor.subscribe('cities');
Meteor.autorun(function() {
Meteor.subscribe('jobs', Session.get('currentIndustryOnet'));
});
Meteor.startup(function(){
if(!Session.get('jobsLoaded'))
Session.set('jobsLoaded', true);
if(! Session.get('map')) {
gmaps.initialize();
}
Deps.autorun(function(){
console.log(Cities.find().count())
});
});
If I log into the mongo shell and run:
db.cities.find().count()
The count returned is 29467, so I know there are records that exist. Not sure what I am doing wrong here
Code Structure:
project_dir/client/client.js
Meteor.subscribe('cities');
Meteor.autorun(function() {
Meteor.subscribe('jobs', Session.get('currentIndustryOnet'), function(){
console.log(Cities.find({}).count());
});
});
project_dir/server/server.js
Meteor.publish('jobs', function(onet_code){
var cursor, options = {sort: {"dateacquired": -1}};
if(onet_code && onet_code != 'all'){
cursor = Jobs.find({onet: onet_code}, options);
} else {
cursor = Jobs.find({}, options);
}
return cursor;
});
Meteor.publish('cities');
project_dir/model.js:
Cities = new Meteor.Collection("cities");
Jobs = new Meteor.Collection("jobs");
Jobs.allow({
insert: function(id) {
return false;
},
update: function(id, options) {
return true;
}
});
createJob = function(options) {
var id = Random.id();
var onet = Session.get('currentIndustryOnet')
Meteor.call('createJob', _.extend({_id: id}, options));
return id;
}
Meteor.methods({
createJob: function(options) {
var id = options._id || Random.id();
Jobs.insert({
_id: id,
lat: options.lat || '',
lng: options.lng || '',
title: options.title,
url: options.url,
company: options.company,
address: options.address,
dateacquired: options.dateacquired,
onet: options.onet,
jvid: options.jvid
});
return id;
}
})
You need to publish your cities collection:
Instead of :
Meteor.publish("cities")
You should have :
Meteor.publish("cities", function() {
return Cities.find()
});

Using $inc to increment a document property with Mongoose

I would like to increment the views count by 1 each time my document is accessed. So far, my code is:
Document
.find({})
.sort('date', -1)
.limit(limit)
.exec();
Where does $inc fit in here?
Never used mongoose but quickly looking over the docs here it seems like this will work for you:
# create query conditions and update variables
var conditions = { },
update = { $inc: { views: 1 }};
# update documents matching condition
Model.update(conditions, update).limit(limit).sort('date', -1).exec();
Cheers and good luck!
I ran into another problem, which is kind of related to $inc.. So I'll post it here as it might help somebody else. I have the following code:
var Schema = require('models/schema.js');
var exports = module.exports = {};
exports.increase = function(id, key, amount, callback){
Schema.findByIdAndUpdate(id, { $inc: { key: amount }}, function(err, data){
//error handling
}
}
from a different module I would call something like
var saver = require('./saver.js');
saver.increase('555f49f1f9e81ecaf14f4748', 'counter', 1, function(err,data){
//error handling
}
However, this would not increase the desired counter. Apparently it is not allowed to directly pass the key into the update object. This has something to do with the syntax for string literals in object field names. The solution was to define the update object like this:
exports.increase = function(id, key, amount, callback){
var update = {};
update['$inc'] = {};
update['$inc'][key] = amount;
Schema.findByIdAndUpdate(id, update, function(err, data){
//error handling
}
}
Works for me (mongoose 5.7)
blogRouter.put("/:id", async (request, response) => {
try {
const updatedBlog = await Blog.findByIdAndUpdate(
request.params.id,
{
$inc: { likes: 1 }
},
{ new: true } //to return the new document
);
response.json(updatedBlog);
} catch (error) {
response.status(400).end();
}
});