NeDB How can i use variable in find query? - find

how can i use variable in my find query, something like this:
db have docs like
{choices:{'04-09-2017':'a'},b:'b'},
{choices:{'04-10-2017':'a'},c:'c'}
my query is
var x = "choices.04-09-2017"
db.find({
x: {
$exists: true
}
}, function(err, docs) {
});
How i can define that x is a variable not is a property?
Thanks!

it is easier if you define an object that represent your search:
var toFind = {};
var firstTerm = "choices";
var secondTerm = "04-09-2017";
toFind[firstTerm]={};
toFind[firstTerm][secondTerm] = {$exists = true};
db.find(toFind, function(err, docs) {
// put here your callback
});
this should work.
in your example x in
{
x: {
$exists: true
}
}
is treated as the key of the obj searched and is not evaluated.

Related

Complicated search in MongoDB

I have defined a PostSchema as follows. A post is written by an author, and can be read by many people: lastOpens is an array of { time: ... , userId: ... }.
var PostSchema = new mongoose.Schema({
title: { type: String }
author: { type: mongoose.Schema.Types.ObjectId, ref: 'user' },
lastOpens: { type: Array, default: [] }
})
Now, I want to write a static method that returns all the posts read by one user:
PostSchema.statics.postsOpenedByUser = function (userId, cb) {
// need to go through all the posts, and check their `lastOpens`.
// If `userId` is in `userId` of a `lastOpen`, then count the post in
}
What I know is the methods like find({ ... }) of MongoDB. But I don't know how to specify a more complicated search like mine.
Could anyone help?
Edit 1: I tried to use $where operator as follows, it did not work:
PostSchema.statics.postsOpenedByUser = function (userId, cb) {
return this.find({ $where: function () {
var index = -1;
for (var i = 0; i < this.lastOpens.length; i++)
if (this.lastOpens[i].userId === userId) { index = i; break }
return !(index === -1)
}}, cb)
Is there anything we could not do inside $where?
You can use Mongo's query an array of embedded documents.
In your case it will look something like :
PostSchema.statics.postsOpenedByUser = function (userId, cb) {
return this.find( { "lastOpens.userId" : userId }, cb );
}
This will return all posts that have userId in the lastOpens

Querying nested objects in mongodb

I am trying to query a User collection with multiple nested objects, and I'm not sure how to properly use the projection operators (e.g. $) as they seem to work for arrays not objects.
Each user has a "booksRecords" object, with multiple book objects (e.g. hc_1_3, hc_1_4, etc). Each book object has a field called currLevel and I am trying to find kids that have at least one book object where currLevel: 'nursery'.
I tried doing
User.find({'booksRecords.$.currLevel': 'nursery'}), but that doesn't seem to be working and I wonder what is the correct way to query nested objects?
I checked Querying nested in mongoDB, but it is different from my case as I'm querying nested objects.
[
//first object
{
_id: "xxx",
booksRecords: {
hc_1_3: {
markedRead: false,
currLevel: "elementary"
},
hc_1_2: {
markedRead: false,
currLevel: "elementary"
}
}
},
//second object
{
_id: "xyz",
booksRecords: {
hc_1_3: {
markedRead: false,
currLevel: "elementary"
},
hc_1_2: {
markedRead: false,
currLevel: "nursery"
}
}
}
]
$ projection applies to array only.
You need to use $where to evaluate each document:
db.User.find( { $where: function() {
for (var i=0 in this.booksRecords) {
if (this.booksRecords[i].currLevel === 'nursery') {
return true;
}
}
return false;
} });
can you please this:
var userList = db.User.find();
var booksRecordsList={};
while(userList.hasNext()){
var user = userList.next();
for(var key in user.booksRecords){
if ( !( key in booksRecordsList ) ) {
booksRecordsList[key] = key;
}
}
};
db.User.find().forEach(function(doc){
for (var booksRecord in booksRecordsList){
var booksRecordItem = doc.booksRecords[booksRecord];
if(booksRecordItem.currLevel == "nursery"){
print(tojson(doc));
}
}
});

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}}

Does Meteor have a distinct query for collections?

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);
};

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();
}
});