How to use $elemMatch in kinvey-flex-sdk? - mongodb

Is there any way, how to use $elemMatch Projection Operators in kinvey-flex-sdk.

You can try this way.
var dataStore = modules.dataStore({ skipBl: true, useMasterSecret: true });
var collection = dataStore.collection('<collectionName>');
var query = new Kinvey.Query();
query.equalTo('items', { $elemMatch: { item: 'a', qty: { $gte: 23 } } });
collection.find(query, function (error, result) {
});

Related

How to user inner query with mongoDB update operation?

i'm trying to write an update query to update a column/filed of a collection. My collection has 4 fields: _id, name, date1, date2.
I'm trying to write an update query to set date1 = date2 and i tried using inner query as shown below but didn't work.
db.myCollection.updateMany(
{},
{
'$set':
{
'date2': db.myCollection.find({},{date1:1, _id:0}).limit(1)
}
}
);
Maybe something like this( version 4.2+):
db.collection.update({},
[
{
$addFields: {
date1: "$date2"
}
}
],
{
multi: true
})
playground
For your case ( Version 3.6 ):
db.collection.find().forEach(
function (elem) {
db.collection.update(
{
_id: elem._id
},
{
$set: {
date1: elem.date2
}
}
);
}
);
var cursor = db.collection.find()
var requests = [];
cursor.forEach(document => {
requests.push( {
'updateOne': {
'filter': { '_id': document._id },
'update': { '$set': { 'date1': document.date2 } }
}
});
if (requests.length === 500) {
//Execute per 500 operations and re-init
db.collection.bulkWrite(requests);
requests = [];
}
});
if(requests.length > 0) {
db.collection.bulkWrite(requests);
}

MongoDB + Mongoose Aggregate w/ Asnyc

I've got the following route in my express file, which takes parameters passed in from a middleware function and queries my backend MongoDB database. But for some reason, it only ever returns an empty array.
I'd like to convert the Mongoose model that allows me to use aggregate functions into async/await to conform with the rest of my code. It's online here.
module.exports = {
search: asyncWrapper(async(req, res, next) => { // Retrieve and return documents from the database.
const {
filterTarget,
filter,
source,
minDate,
maxDate,
skip,
limit,
sortBy,
sortOrder
} = req.search;
try {
const mongoData = await Model.aggregate([
{
$match: {
date: {
$gt: minDate, // Filter out by time frame...
$lt: maxDate
}
}
},
{
$match: {
[filterTarget]: filter // Match search query....
}
},
{
$set: {
[filterTarget]: { $toLower: `$${filterTarget}` } // Necessary to ensure that sort works properly...
}
},
{
$sort: {
[sortBy]: sortOrder // Sort by date...
}
},
{
$group: {
_id: null,
data: { $push: "$$ROOT" }, // Push each document into the data array.
count: { $sum: 1 }
}
},
{
$project: {
_id: 0,
count: 1,
data: {
$slice: ["$data", skip, limit]
},
}
}
])
return res.status(200).json({ data: mongoData.data || [], count: mongoData.count || 0 });
} catch (err) {
next(err);
}
})
};
For some reason, the route is only returning an empty array every time. I've double and triple checked my variables, they are not the problem.
How can I use the Mongoose.aggregate() function in an async await route?

Building MongoDB query with conditions

I need to build a MongoDB query by pushing a new language if it does not exist in the array already. But if it exists I get an error this '$push' is empty. It is correct.
My question is how to build the query adding $push only when it is necessary?
let pushNewLanguage = {};
if (!profile.languages || (profile.languages && !profile.languages.find(l => l === languageId))) {
pushNewLanguage = { languages: languageId };
}
const profileUpdate = await
Profiles.rawCollection().update(
{ userId: this.userId },
{
$inc: { countPublishedPoems: 1 },
$push: pushNewLanguage
}
);
Remove the conditional logic and use $addtoSet instead of $push.
$addToSet will only add the item if it doesn’t exist already.
const profileUpdate = await
Profiles.rawCollection().update(
{ userId: this.userId },
{
$inc: { countPublishedPoems: 1 },
$addToSet: { languages: languageId }
}
);
Since you are writing Javascript, you can create a "base" update object, and then add the $push property if you need:
const update = {
$inc: { countPublishedPoems: 1 }
}
if (!profile.languages || (profile.languages && !profile.languages.find(l => l === languageId))) {
update["$push"] = { languages: languageId };
}
const profileUpdate = await
Profiles.rawCollection().update(
{ userId: this.userId },
update
);

Getting an avarage value from MongoDB

I have this mongoose model:
var juomaSchema = new mongoose.Schema({
...
valikoima: String,
img: String,
views: {default: 0, type: Number},
rating: [],
...
});
juomaSchema.methods.getAvarageRating = function() {
if (this.rating.length !== 0) {
var totalScore = 0;
this.rating.forEach(function(drinkRating) {
totalScore += drinkRating
});
return totalScore/this.rating.length;
} else {
return 0;
}
};
My problem is, that I need to sort a query by the avarage rating of the rating field.
I already have the method in the model, but I can't seem to use a function inside a sort query.
Here's my sort:
router.get("/oluet", function(req, res) {
var perPage = 20,
page = req.query.page,
sortBy = req.query.sort,
asc = req.query.asc;
var sort = {[sortBy] : asc};
console.log(sort);
if(req.xhr) {
//Sanitazes input
const regex = new RegExp(escapeRegExp(req.query.search), "gi");
Juoma.find({nimi: regex, tyyppi: "oluet"})
.sort(sort)
.limit(perPage)
.skip(perPage * page)
.exec(function(err, drinks) {
How would I do this? Making two fields: totalRating and timesRates, and doing some aggregation magic?
Felix solved this in the comments with
{
$project: {
avg: {$avg: "$rating"}
}
}

Mongoose's find method with $or condition does not work properly

Recently I start using MongoDB with Mongoose on Nodejs.
When I use Model.find method with $or condition and _id field, Mongoose does not work properly.
This does not work:
User.find({
$or: [
{ '_id': param },
{ 'name': param },
{ 'nickname': param }
]
}, function(err, docs) {
if(!err) res.send(docs);
});
By the way, if I remove the '_id' part, this DOES work!
User.find({
$or: [
{ 'name': param },
{ 'nickname': param }
]
}, function(err, docs) {
if(!err) res.send(docs);
});
And in MongoDB shell, both work properly.
I solved it through googling:
var ObjectId = require('mongoose').Types.ObjectId;
var objId = new ObjectId( (param.length < 12) ? "123456789012" : param );
// You should make string 'param' as ObjectId type. To avoid exception,
// the 'param' must consist of more than 12 characters.
User.find( { $or:[ {'_id':objId}, {'name':param}, {'nickname':param} ]},
function(err,docs){
if(!err) res.send(docs);
});
I implore everyone to use Mongoose's query builder language and promises instead of callbacks:
User.find().or([{ name: param }, { nickname: param }])
.then(users => { /*logic here*/ })
.catch(error => { /*error logic here*/ })
Read more about Mongoose Queries.
You can also add a mix of $or and and to give your functions more flexibility, options and robustness, like so:
var ObjectId = require("mongoose").Types.ObjectId;
var idParam = new ObjectId(param.length < 12 ? "123456789012" : param);
const {nameParam, nicknameParam, ageParam} = req.params || req.body || req.query
User.find({
$or: [{
_id: objId
},
{
name: nameParam
},
{
nickname: nicknameParam
}
],
$and: [{
age: ageParam
}]
},
function (err, docs) {
if (!err) res.send(docs);
}
);
So this means that your find() will look for all users where (_id = idParam OR name = nameParam OR nickname = nicknameParam) AND (age = ageParam)
I hope this helps someone out there.
Cheers!!!