MongoDB to return assoc array of results - node.js

My collection has object with the following form
{'id':2, 'name':'john', 'avatar':'img.png'},
{'id':3, 'name':'chriss', 'avatar':'img2.png'}
After i query mongo, i want to get the following results
{'2': {'id':2, 'name':'john', 'avatar':'img.png'}, '3':{'id':3, 'name':'chriss', 'avatar':'img2.png'}}
Is it possible to do this with mongo or do i have to iterate over the results to get this form ?

You could try iterating over the results using the find() cursor's forEach() method as follows :
var obj = {};
db.collection.find({}, {"_id": 0}).forEach(function(doc){
obj[doc.id.toString()] = doc;
});
printjson(obj);
Or using the map() method:
var mapped = db.collection.find({}, {"_id": 0}).map(function(doc){
var obj = {};
obj[doc.id.toString()] = doc;
return obj;
});
printjson(mapped);
Output in both methods:
{
"2" : {
"id" : 2,
"name" : "john",
"avatar" : "img.png"
},
"3" : {
"id" : 3,
"name" : "chriss",
"avatar" : "img2.png"
}
}

Related

Query to find document by matching a value in an object embeded in an array field

I want to query a collection "chat" whose documents have an array field "participants". This array has always two objects with the properties id and name. I want to find the document that matches the two ids of the embeded objects. For example, I want to find the following document in which the ids are "1" and "2".
//chat
//find ids 1 and 2.
//this is the document that I am looking for and should be returned.
{
_id : ytyutu876788
participants : [ {id : 1, name : Murray}, {id : 2, name : Pier} ]
}
//In this document id 1 is present but not together with id 2.
{
_id : d6t6d6tdt6
participants : [ {id : 1, name : Murray}, {id : 3, name : Gustav} ]
}
The query that I have tried to use so far is the following which returns an empty array even though I am sure that the document that I want to find exists in the collection so I know that it is the query what I am doing wrong:
try {
const userId = req.body.userId
const friendId = req.body.friendId
console.log(userId)
console.log(friendId)
await client.connect()
const query = await client.db('instagram_clone').collection('chat').find(
{"participants.id" : {userId, friendId}}
).toArray()
console.log(query)
You may use $all operator like
const query = await client.db('instagram_clone')
.collection('chat')
.find({"participants.id": {$all:[userId, friendId]}})
.toArray();
Or you may like to use $and operator like
const query = await client.db('instagram_clone')
.collection('chat')
.find({$and :[{"participants.id": userId}, {"participants.id": friendId}]})
.toArray();
This another query that does the job, in which I used the $elemmatch operator.
const firstQuery = await client.db('instagram').collection('chat').find({
participants : {
$all: [
{
$elemMatch: {
id: friendId
}
}, {
$elemMatch: {
id: userId
}
}
]
}
}).toArray();

How to compare mongoDB ObjectIds & remove duplicates in an array of documents using node.js?

I have an array called "doc" which contains a list, in which some of them contains same ref object id, I have to remove that duplicate, but none of the code is working because I'm filtering according to ref object id, which is in the form of object. I have to access the id inside the object and filter it according to that object id. here userId is the referance object id.
Answer.find({'blockId': questId}, (err, doc) => {
if(doc!=null){
userId = 0;
userList = [];
userIdd = 0;
uslist = [];
for(var i = 0; i<doc.length; i++){
if(userId != doc[i].userId){
userIdList.push({'userId':doc[i].userId});
userId = doc[i].userId;
}
}
}else{
}
});
If you're getting doc[i].userId field values as ObjectId()'s from DB, then try this :
Answer.find({ 'blockId': questId }, (err, doc) => {
if (err) {
// return here itself
}
let userId = '';
let userIdList = [];
if (doc.length) {
for (var i = 0; i < doc.length; i++) {
/** Since we're using mongoose use `.toHexString()` to convert to string & compare,
if you're using mongoDB driver use `toString()` to convert to string */.
if (userId != (doc[i].userId).toHexString()) {
userIdList.push({ 'userId': doc[i].userId });
userId = (doc[i].userId).toHexString();
}
}
} else {
console.log('No matching answers found for blockId ::', questId)
}
})
Above code should work via Node.Js, just in case if your intention is all about just to get unique userId's try this as it helps to achieve things in DB itself in quick :
Answer.aggregate({$match : {"blockId" : 1}},
{$group : {_id : {blockId: '$blockId'},userIds: {$addToSet : '$userId'} }}).lean(true).exec((err, doc)=> {})
Collection Data :
/* 1 */
{
"_id" : ObjectId("5e103f0b400289966e01dc47"),
"blockId" : 1,
"userId" : ObjectId("5dfeac7b400289966e2042c7")
}
/* 2 */
{
"_id" : ObjectId("5e103f34400289966e01e1f9"),
"blockId" : 1,
"userId" : ObjectId("5dfeac7b400289966e2042c5")
}
/* 3 */
{
"_id" : ObjectId("5e103f4a400289966e01e56c"),
"blockId" : 1,
"userId" : ObjectId("5dfeac7b400289966e2042c7")
}
/* 4 */
{
"_id" : ObjectId("5e103f51400289966e01e678"),
"blockId" : 1,
"userId" : ObjectId("5dfeac7b400289966e2042c6")
}
/* 5 */
{
"_id" : ObjectId("5e103f57400289966e01e793"),
"blockId" : 1,
"userId" : ObjectId("5dfeac7b400289966e2042c1")
}
/* 6 */
{
"_id" : ObjectId("5e103f61400289966e01e92b"),
"blockId" : 2,
"userId" : ObjectId("5dfeac7b400289966e2042c9")
}
/* 7 */
{
"_id" : ObjectId("5e1040c3400289966e021168"),
"blockId" : 1,
"userId" : ObjectId("5dfeac7b400289966e2042c5")
}
Result :
/* 1 */
/** Duplicates removed */
{
"_id" : {
"blockId" : 1
},
"userIds" : [
ObjectId("5dfeac7b400289966e2042c1"),
ObjectId("5dfeac7b400289966e2042c6"),
ObjectId("5dfeac7b400289966e2042c5"),
ObjectId("5dfeac7b400289966e2042c7")
]
}
Or if you just wanted to use .find() & still do it in node.js, again if your operation is all about unique userId's, then at-least add projection to your code in order to retrieve only needed fields from DB :
Answer.find({ 'blockId': questId }, {_id :0, 'blockId':1, userId:1 }, (err, doc) => { })
I got a simple solution for this.
if 'doc' is the array which contains duplicates.
userIdList = [];
userIdList = Object.values(doc.reduce((acc,cur)=>Object.assign(acc,{[cur.userId.toString()]:cur}),{}));

Making third collection out of two collections and want all of fields in the third collections in MONGODB

var mapDevice = function(){
var values = {
Device_Id: this.Device_Id,
Module_Id : this.Module_Id,
Area_Id: this.Area_Id,
Gas_Id: db.Reading.findOne({Gas_Id: db.Reading.Gas_Id})
};
emit(this.Device_Id, values);
};
var mapReading = function(){
var values = {
Device_Id :this.Device_Id,
Gas_Id :this.Gas_Id
Module_Id: db.Device.findOne({Module_Id: db.Device.Module_Id}),
Area_Id: db.Device.findOne({Area_Id: db.Device.Area_Id})
};
emit(this.Device_Id, values);
};
var reduce = function(key, values){
var outs ={
Device_Id: null,
Module_Id : null,
Area_Id: null,
Gas_Id: null
};
values.forEach(function(v){
if(outs.Device_Id ==null){
outs.Device_Id = v.Device_Id
}
if(outs.Module_Id ==null){
outs.Module_Id = v.Module_Id
}
if(outs.Area_Id==null){
outs.Area_Id = v.Area_Id
}
if(outs.Gas_Id==null){
outs.Gas_Id = v.Gas_Id
}
});
return outs;
};
db.Reading.mapReduce(mapReading,reduce,{
out: { merge: "map_reduce_example" },
query: { 'Concentration':{ $gt: 3 }}
});
db.Device.mapReduce(mapDevice,reduce,{
out: { merge: "map_reduce_example" }
});
///////// DEVICE COLLECTION
{
"_id" : ObjectId("5a89cb9b7c417b7a8fc07a91"),
"Device_Id" : "DEEV2",
"Module_Id" : "MOD1",
"Area_Id" : "SUM"
}
//////////READING COLLECTION
{
"_id" : ObjectId("5a893d946fa0c25613c14427"),
"device_id" : "DEEV1",
"Gas_Id" : "CO2",
"Concentration" : 401
}
/////////MAP_REDUCE_EXAMPLE COLLECTION
{
"_id" : null,
"value" : {
"Device_Id" : null,
"Module_Id" : undefined,
"Area_Id" : undefined,
"Gas_Id" : "CO2"
}
}
Been trying to merge 2 collections and make 3rd out of it using MAPREDUCE in mongodb. Want field included in the third(new) collection not only common ones but all of them. My two collections are DEVICE and READING and I want to have the collection map_reduce_example collection(which i am getting null values).
Following are the supporting screenshots to my code:
[![This is ss of my "**Reading**" collection][1]][1]
[![This is ss of my "**Device**" collection][2]][2]
[![This is how i want my final collection to be i.e **"map_reduce_example"** collection to be][3]][3]
[1]: https://i.stack.imgur.com/qNkNR.png
[2]: https://i.stack.imgur.com/v6sFK.png
[3]: https://i.stack.imgur.com/AzTqO.png

How to pass mongodb match conditions from node.js URL parameters

I have a webpage where users selects variables to filter and get database values. I tried passing the $match condition variables as below but i am not getting any results back
URL is : example.com?gender=M&date_from=20100101&date_to=201140101
I loop through the req.query to build the match condition string.
var matchQuery = [];
for (var param in req.query) {
qString = "{'" + param + "' : '" + req.query[param] + "'}";
matchQuery.push(qString);
}
var strmatchQuery = matchQuery.toString();
This outputs strmatchQuery as {'gender' : 'M'}, {'date_from' : '20100101'}, {'date_to' : '20140101'}
and then I call the mongodb aggregate function
dbmodel.aggregate( { $match: { $and: [ strmatchQuery ]} } , { $group : { _id : "$orderyear", totalorders : { $sum : 1 } } } )
But I dont get any results back. Any ideas?
function is_numeric(num) {
return !isNaN(num);
}
var matchQuery = [];
var qString = {};
for (var param in req.query) {
// You need objects in your query not strings so push objects
qString = {};
qString[param] = is_numeric(req.query[param]) ? Number(req.query[param]) : req.query[param];
matchQuery.push(qString);
}
// Removed the toString() function call
dbmodel.aggregate(
{$match: {$and: strmatchQuery}}, // Removed the array [ ]
{$group: {
_id: "$orderyear",
totalorders: {$sum: 1}}
}
);

mongoose "_id" vanishing in collection created with map/reduce

I done a very simple map/reduce in mongo console.
var mapState = function () {
emit(this.state, 1);
};
var sumState = function (keyState, valuesCount) {
return Array.sum(valuesCount);
};
db.FooBar.mapReduce(
mapState,
sumState,
{out: "state_counts"}
);
var sc = {};
db.state_counts.find(
{_id: {$exists: true}}).forEach(
function(o){
sc[o._id]=o.value;
}
);
> sc
{
"ak" : 29,
"al" : 5832,
"ar" : 2798,
...
}
> db.state_counts.find().limit(3)
{ "_id" : "ak", "value" : 29 }
{ "_id" : "al", "value" : 5832 }
{ "_id" : "ar", "value" : 2798 }
So far so good. I have the expected state abbreviations and counts in the "sc" object. Oddness occurs when I'm attempting to pull data from state_counts prior to converting it to the equivalent of the "sc" object using mongoose.
#!/usr/bin/env node
mongoose = require("mongoose");
mongoose.connect("mongodb://localhost/thedb");
var schema = new mongoose.Schema({});
schema.collection = 'state_counts';
console.log(schema.collection);
var cur = mongoose.model(schema.collection, schema);
cur.find({}).exec(
function(err, data) {
if (err) {
console.log(err);
mongoose.disconnect();
}
console.log(data);
mongoose.disconnect();
}
);
$ ./test.js
state_counts
[ { value: 29 },
{value: 5832 },
{ value: 2798 },
...
]
This is surprising to me. Why is the "_id" value not showing up in my script when using mongoose?
_id isn't showing up because you haven't defined a schema and mongoose is all about adding schemas to mongodb. So given a completely empty schema, mongoose probably assumes _id will be of type ObjectId (which is conventional for mongodb) and when casting the data in mongodb to that type fails, as it will always do given your data, mongoose omits the value, which makes sense given the majority of mongoose's job is to enforce a consistent schema. This will "fix" it.
var schema = new mongoose.Schema({_id: String, value: Number});

Resources