nodejs mongodb $in [array] not working if array is a variable - node.js

This is very strange to me. If put the array onlyIds in the aggregation query of my db I get no results. If I however put the content of onlyIds that I get printed from line 5 which looks like:
["52e953942a13df5be22cf792","52e953942a13df5be22cf793","52e953942a13df5be22cf797"...]
Then it works. But not if I use the variable.
This function:
var onlyIds = [];
for (var i = 0; i < users.length; i++) {
onlyIds.push(users[i]._id);
}
console.log("ids: " + JSON.stringify(onlyIds)); <---------- not empty
db.collection('posts', function(err, collection) {
collection.aggregate([
{$match: {user_id: {$in: onlyIds}}}, <------- not working
{$match: {created:{$gte: 0}}},
{$sort:{"created": -1}},
{$skip: req.body.skip},
{$limit: req.body.limit}
],
function(err, posts) {
var errorNo, content, message;
if (err) {
errorNo = resSend.errorDB;
message = JSON.stringify(err);
} else {
errorNo = resSend.errorNo;
content = posts;
message = "";
--> console.log(JSON.stringify(posts));
}
resSend.sendResponse(res, resSend.errorNo, content, message);
});
});
So in short, why does this work:
{$match: {user_id: {$in: ["52e953942a13df5be22cf792","52e953942a13df5be22cf793","52e953942a13df5be22cf797"...]}}}
and this doesn't:
{$match: {user_id: {$in: onlyIds}}}
And the line that does not work, works perfectly in another function. Any ideas or enlightenments?
EDIT:
Switching to find and using the below answer like this:
collection.find({'user_id': {$in: onlyIdsX}}).toArray(function(err, posts)
does not work either.
ANSWER:
As the selected answer indicates below is when the variable you search for is an ObjectId or a string. For anyone else, make sure that the variable in the db is the same type as the one you try to match it with. In my case both were supposed to be strings, but one's in "onlyIds" were ObjectIds.

Try following code to modify your loop:
var ids = ["52e953942a13df5be22cf792","52e953942a13df5be22cf793","52e953942a13df5be22cf797"];
var obj_ids = [];
for (var i = 0; i < users.length; i++) {
obj_ids.push(new ObjectID(users[i]._id.toString()));
var obj_ids.push(users[i]._id); // <== This will not work if your DB has _id : ObjectID("xyz") [i.e. you are not overiding defaults]
}
And you should include var ObjectID = require('mongodb').ObjectID; into your code.
You should use .toArray(function(err,.. (Not in your case since you used aggregation framework).This will also cause issue if you are not using findOne() (For more info on this here is the link)
Following is the example which spots the issue (in comments) & working Code:
var mongo = require('mongodb'),
Server = mongo.Server,
Db = mongo.Db,
ObjectID = require('mongodb').ObjectID;
var BSON = require('mongodb').BSONPure;
var server = new Server('localhost', 27017, {
auto_reconnect: true
});
var MongoClient = require('mongodb').MongoClient
//let id = your _id, smth like '6dg27sh2sdhsdhs72hsdfs2sfs'...
var users = ["52e953942a13df5be22cf792","52cbd028e9f43a090ca0c1af","52e953942a13df5be22cf797"];
var obj_ids = [];
for (var i = 0; i < users.length; i++) {
obj_ids.push(new ObjectID(users[i].toString()));
//obj_ids.push(users[i]._id); // <== This will not work if your DB has _id : ObjectID("xyz") [i.e. you are not overiding defaults]
}
MongoClient.connect('mongodb://127.0.0.1:27017/YourDBName', function(err, db) {
console.log('err' + err);
db.collection('posts', function(error, collection) {
//collection.find({_id:{$in: users}}),function(err, docs) { //This will not work
collection.find({_id:{$in: obj_ids}}).toArray(function(err, docs) {
console.log("Printing docs from Array. count " + docs.length);
docs.forEach(function(doc) {
console.log("Doc from Array ");
console.dir(doc);
});
});
});
});

Related

How would I go about querying MongoDB efficiently using Mongoose?

I'm trying to query MongoDB with text.
Say I enter "Oven", the server should find all contraptions and users, including the word "Oven" in a field called "title" for contraptions and a field called "username" for users.
Right now, my code looks like this:
const foundContraptions = await Contraptions.find({});
const foundUsers = await Profiles.find({});
const filteredContraptions = QueryContraptions(foundContraptions, query);
const filteredUsers = QueryUsers(foundUsers, query);
function QueryContraptions(arr, query) {
const filtered = [];
for (let i = 0; i < arr.length; i++) {
const contraption = arr[i];
if (contraption.title.toLowerCase().includes(query.toLowerCase())) {
filtered.push(removeFile(contraption));
}
}
return filtered;
}
function QueryUsers(arr, query) {
const filtered = [];
for (let i = 0; i < arr.length; i++) {
const user = arr[i];
if (user.username.toLowerCase().includes(query.toLowerCase())) {
filtered.push(removeToken(user));
}
}
return filtered;
}
This works perfectly fine, but assuming I have a lot of data in my DB, at some point I would get an Error HeapOutOfMemory, or it would take a long time to execute the loops.
So I wanted to ask how I would go about querying MongoDB efficiently using Mongoose.
I managed to find an answer by myself using the MongoDB query operators
const contraption = await Contraptions.find({ 'title': { '$eq': query } }).catch(err => { console.log(err); });
https://docs.mongodb.com/manual/reference/operator/query/

NodeJS with MongoDB - Trying to use two different collections data

I have the following code:
var res1 = db.collection('col1').find(query1).toArray();
var res2 = db.collection('col2').find(query2).toArray();
Promise.all([res1, res2])
.then(([resultRes1, resultRes2]) => {
console.log('resultRes1', res1);
console.log('resultRes2', res2);
debugger;
}).catch(console.error);
Now, each one of them is working great separately
my problem is that i want to run a function when both of them are done.
if i try to nest them i keep getting a "mongodb topology was destroyed" alert (even though all i do is read from those collection - i am not changing anything
any ideas? many thanks.
Post the code where you are trying to run something where both are done. Are you trying something like this?
var res1 = db.collection('col1').find(query1);
var res2 = db.collection('col2').find(query2);
Promise.all([res1, res2])
.then(([resultRes1, resultRes2]) => {
console.log('resultRes1', resultRes1);
console.log('resultRes2', resultRes2);
})
.catch(console.error);
var collection = db.collection(collection1);
var Res = collection.aggregate([{
$lookup: {
from: "collection2",
localField: "ID",
foreignField: "ID",
as: "Sample"
}
}], function(err, result) {
if (result != null) {
for (var i = 0; i < result.length; i++) {
delete result[i].Sample;
}
res.send(result);
}
})
};

get name from id inside loop in node js

hello all I am new to node js and mongo db so I am facing a problem which is written above want to match an id from an array and get all the record of matching id , but thats not working i have already tried for loop but that is taking too much time so i am looking for some kind of query by which I pass id and get the matching results i have below function also where i can pass id and get the matching result but i don't know how to call that .
exports.getDistrictFromId = function(req, res, next) {
var distId = req.params.id;
districtslib.getDistricts({_id: utils.toObjectId(distId)}, function(err, district) {
if (err) {
return next(err);
}
req.store.district = district;
next();
});
};
Here is my code
exports.getCompleteTeachersList = function(req, res, next) {
var query = req.store.get('query');
var teacherQuery = {enabled: true};
var searchQuery = '';
if (!_.isUndefined(query)) {
// schoolQuery = {'name':new RegExp(query.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"),'i')};
//{ $text: { $search: "amit hinduja"} }
//teacherQuery = {enabled: true,$or:[{firstName:new RegExp(query.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"),'i')},{lastName:new RegExp(query.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"),'i')}]};
if(query.trim() != '') {
teacherQuery = {enabled: true,$text: { $search: query} };
searchQuery = query;
}
}
teacherslib.getTeachers(teacherQuery, function(err, teachers) {
if (err) {
return next(err);
}
var schools = req.store.get('schools');
for(var i = 0; i < teachers.length; i++) {
teachers[i].schoolName = "";
for(var j = 0; j < schools.length; j++) {
if (teachers[i].schoolId.toString() === schools[j]._id.toString()) {
teachers[i].schoolName = schools[j].name;
teachers[i].distId = "";
var districts = req.store.get('districts');
console.log(schools[j].distId);
// i want to get the array of matching district id `schools[j].distId` from the district array from `var districts = req.store.get('districts');` this line
break;
}
}
}
req.store.set('searchQuery', searchQuery);
req.store.set('teachers', teachers);
//req.store.set('districts', districts);
next();
});
};
Collection structure is like this
1) distid is coming in schools collection
using distid get all the matching record from district
2)district array has countyid and from that county id has to get data from the county collection
Instead of looping inside a loop, i would suggest you look into the $lookup operator of the aggregation framework. Here you can perform the lookup server side.

why update doesn't work

I pass a json variable to a module but I can't do the update of my collection, always I have an error in the updating.
var gestion = function(myJSON) {
var dburl = 'localhost/mongoapp';
var collection = ['clientes'];
var db = require('mongojs').connect(dburl, collection );
function cliente(nombre, estado, nuevo){
this.nombre = nombre;
this.estado = estado;
this.nuevo = nuevo;
}
var cliente1 = new cliente(myJSON.nombre myJSON.estado, myJSON.nuevo);
if (cliente1.estado == "desconectado"){
db.clientes.update(cliente1.nombre, {$set: {estado: "desconectado", nuevo: "no"}}, function(err) {
if (err) console.log("error "+cliente1.nombre);
else console.log("OK");
});
}
}
return 0;
}
I also tried to remove my db and create one more time and I'm sure that my object exist in my db.
The signature you should be using is
update(query, update, callback)
but you're passing a string for query, which doesn't mean anything to Mongo. You may want to look at the docs for an overview, but for this specific instance, it looks like you're trying to find the document where nombre is equal to the string at cliente1.nombre. The query for this is a dictionary { nombre: cliente1.nombre }, so that line should be
db.clientes.update({nombre: cliente1.nombre}, {$set: {estado: "desconectado", nuevo: "no"}}, function(err) {

How to query two collection in mongoose on nodeJs?

hi am new to nodeJs i have to query a table from the result of the query, i have to query another table. i tried the code as follows but it returns only null.
action(function getpositions(req){
var namearray = [];
NHLPlayerStatsDaily.find ({"created_at": {$gt: new Date(y+"-"+m+"-"+d)}}, function(err,position){
if(!err)
{
for (i=0;i< position.length; i++)
{
var obj = JSON.stringify(position[i]);
var pos = JSON.parse(obj);
var p = pos["player_stats_daily"]["content"]["team_sport_content"]["league_content"]["season_content"]["team_content"]["team"]["id"]
NHLTeam.find({"sdi_team_id": p}, "first_name nick_name short_name sport_id", function(err, team){
if (!err){
var obj = JSON.stringify(team);
var pos = JSON.parse(obj);
namearray.push(team)
}
})
}
return send(namearray);
}
})
})
if i just push "p" it shows the result and when am query "NHLTeam" in separate function it also shows the result. when querying a collection with in collection it return null. how to query a collection within a collection in mongoose. thanks in advance.
This is not a query problem, it is callback issue. The send(namearray) is called before any of the NHLTeam queries in the loop are completed (remember the result of these queries is passed to callback asynchronously).
What you can do is this (basically tracking when all callbacks are completed):
NHLPlayerStatsDaily.find ({"created_at": {$gt: new Date(y+"-"+m+"-"+d)}}, function(err,position){
if(!err)
{
var total = position.length;
for (i=0;i< position.length; i++)
{
var obj = JSON.stringify(position[i]);
var pos = JSON.parse(obj);
var p = pos["player_stats_daily"]["content"]["team_sport_content"]["league_content"]["season_content"]["team_content"]["team"]["id"]
NHLTeam.find({"sdi_team_id": p}, "first_name nick_name short_name sport_id", function(err, team){
total--;
if (!err){
var obj = JSON.stringify(team);
var pos = JSON.parse(obj);
namearray.push(team);
}
if(total == 0)
send(namearray);
})
}
}
})

Resources