mongodb collection.find not finding documents - mongodb

Absolute mongodb newbie here, and I must say I'm not impressed by the documentation. Anyway, my problem is I have a database on Mongodb Atlas, a Stitch application with a next.js frontend and trying to retrieve data like this:
import { setStitchClient } from '../utils/stitch';
export default class MyPage extends React.Component {
static async getInitialProps() {
const stitchClient = await setStitchClient();
const db = stitchClient.service('mongodb', 'mongodb-atlas').db('dbName');
await stitchClient.login();
const docs = await db
.collection('test')
.find()
.limit(200)
.execute();
return { docs: docs };
}
render() {...}
The test collection includes 150 documents imported with mongoimport cli. I verified the documents are correctly imported. However the .find() above finds no records and the result is an empty array.
If I create a document through the frontend in another collection, I can find it without problems.
I guess there is no simple answer here but any hint would be highly appreciated. Thanks a lot!

Can you run a find or findOne from the CLI with positive results? Or confirm in Compass that the collection is there, in that db...
Been a while since I did any mongo stuff, but I think you need to add the empty object for the query so
.find({}) or .findOne({})
Consider going with express + mongoose instead of stitch while you are learning to work with mongo. It's the tried and tested setup for a backend using mongo. It will be easier to refactor your code to stitch later on, than to move forward while getting stuck on lacking documentation.
Hope that helps!

first of all, you should import "mongodb" in your model.
if you want use find()
then in your method do this :
db.collection("your collection name")
.find({ _id: mongodb.ObjectID(prodId) })
.next()
.then(product => {
console.log(product);
return product;
})
the "mongodb.ObjectID(id) let you to compare the id and _id in your DB by string.
the next() is so important to process continue
but if you want use findOne({})
do this :
db.collection("products")
.findOne({ _id: mongodb.ObjectID(prodId) })
.then(product => {
console.log(product);
return product;
})

Related

Mongo db Collection find returns from the first entry not from last from client side

I am using mongodb and i am querying the database with some conditions which are working fine but the results are coming from the first entry to last where as i want to query from the last added entry to the collection in database
TaggedMessages.find({taggedList:{$elemMatch:{tagName:tagObj.tagValue}}}).fetch()
Meteor uses a custom wrapped version of Mongo.Collection and Mongo.Cursor in order to support reactivity out of the box. It also abstracts the Mongo query API to make it easier to work with.
This is why the native way of accessing elements from the end is not working here.
On the server
In order to use $natural correctly with Meteor you can to use the hint property as option (see the last property in the documentation) on the server:
const selector = {
taggedList:{ $elemMatch:{ tagName:tagObj.tagValue } }
}
const options = {
hint: { $natural : -1 }
}
TaggedMessages.find(selector, options).fetch()
Sidenote: If you ever need to access the "native" Mongo driver, you need to use rawCollection
On the client
On the client you have no real access to the Mongo Driver but to a seemingly similar API (called the minimongo package). There you won't have $natural available (maybe in the future), so you need to use sort with a descenging order:
const selector = {
taggedList:{ $elemMatch:{ tagName:tagObj.tagValue } }
}
const options = {
sort: { createdAt: -1 }
}
TaggedMessages.find(selector, options).fetch()

Mongoose : don't insert if element already stored

I'm using MongoDB and Mongoose with Express to store tweets that I retrieve via the Twitter API.
I want to avoid saving duplicate tweets. I am doing something like that :
TweetsModel.find({tweet_id: tweet.tweet_id}, function (err, tweets) {
if(tweets.length > 0){
cb('Tweet already exists',null);
} else{
tweet.save(function(err){
cb(err,user);
});
}
});
My question is : for performance reason, is there a way using Mongoose to avoid doing two requests ? One find and one save ?
Knowing that I don't want to update the tweet if it already exists either.
Thank you
You can use an update call with the upsert option to do this:
TweetsModel.update(
{tweet_id: tweet.tweet_id},
{$setOnInsert: tweet},
{upsert: true},
function(err, numAffected) { .. }
);
If a doc already exists with that tweet id, then this is a no-op. Otherwise it will add the doc.
$setOnInsert requires v2.4+ of MongoDB. If your version is less than 2.4, things get more complicated.

Getting Mongoose Schema's and Documents without knowing Schema / Collection names?

Short Version: I basically want to do what show collections does in the mongo shell, in mongoose.
Long Version:
I want to create an application that allows users to basically create their own Schema's > Collections > Documents using mongo + mongoose + node.js.
The first step of this application would be to show previously created Collections and their Documents. But since these would be created by a user their names are not known.
The code I've found that came closest was:
function find (collec, query, callback) {
mongoose.connection.db.collection(collec, function (err, collection) {
collection.find(query).toArray(callback);
});
}
But I don't know what the name of the collection is so I can't pass the 'collec' parameter.
So, anyone know how to get the list of collections without knowing their names?
I ended up using node-mongodb-native (the mongo driver that mongoose works on top of) to get the collection names:
var nmn_connect = require('mongoose/node_modules/mongodb').connect;
nmn_connect('mongo://localhost:27017/DATABASE', function(err, db) {
if(!err){
db.collectionNames(function(err, names){ // what I was looking for
if(!err){
console.log(names);
db.close();
}else{
console.log(err);
db.close();
}
});
}else{
console.log(err)
}
});
The Object returned by mongoose.connect() has no method similar to collectionNames() that I can find.
I know nothing of mongoose, but this page suggests that you could use mongoose.connection.collections to access all collections: http://mongoosejs.com/docs/api.html
each collection again should have a name attribute.
try this:
mongoose.connection.db.collectionNames(function (err, names) {
});

Identify last document from MongoDB find() result set

I'm trying to 'stream' data from a node.js/MongoDB instance to the client using websockets. It is all working well.
But how to I identify the last document in the result? I'm using node-mongodb-native to connect to MongoDB from node.js.
A simplified example:
collection.find({}, {}, function(err, cursor) {
if (err) sys.puts(err.message);
cursor.each(function(err, doc) {
client.send(doc);
});
});
Since mongodb objectId contatins creation date you can sort by id, descending and then use limit(1):
db.collection.find().sort( { _id : -1 } ).limit(1);
Note: i am not familiar with node.js at all, above command is mongo shell command and i suppose you can easy rewrite it to node.js.
Say I have companies collection. Below snippet gives me last document in the collection.
db.companies.find({},{"_id":1}).skip(db.companies.find().count()-1);
Code cannot rely on _id as it may not be on a specific pattern always if it's a user defined value.
Use sort and limit, if you want to use cursor :
var last = null;
var findCursor = collection.find({}).cursor();
findCursor.on("data", function(data) {
last = data;
...
});
findCursor.on("end", function(data) {
// last result in last
....
});

Finding an Embedded Document by a specific property in Mongoose, Node.js, MongodDB

For this app, I'm using Node.js, MongoDB, Mongoose & Express
So I have a Param Object that contains an array of Pivots, and I want to read certain data from the pivots as outlined below
---in models.js-------------------------
var Pivot = new Schema({
value : String
, destination : String
, counter : Number
});
var Param = new Schema({
title : String
, desc : String
, pivots : [Pivot]
});
------------- in main.js --------------
var Param = db.model('Param');
app.get('/:title/:value', function(req, res){
Param.findOne({"title":req.param('title')}, function(err, record){
console.log(record.pivots);
record.pivots.find({"value":req.param('value')}, function(err, m_pivot){
pivot.counter++;
res.redirect(m_pivot.destination);
});
record.save();
});
});
I know that the code works until console.log(record.pivots), since i got a doc collection with the right pivot documents inside.
However, there does not seem to be a find method to let me match an embedded document by the 'value' property defined in the schema. Is it possible to search through this array of embedded documents using .find() or .findOne() , and if not, is there some easy way to access it through mongoose?
varunsrin,
This should do it
app.get('/:title/:value', function(req, res) {
Param.findOne({'pivots.value': req.param('value'), "title":req.param('title')}},
function(err, record) {
record.pivot.counter++;
res.redirect(m_pivot.destination);
record.save();
});
});
Note the pluralization of the query to match the field name in your schema
You can querying using embedded document properties like this:
{'pivot.value': req.param('value')}}
Update in response to comment:
app.get('/:title/:value', function(req, res) {
Param.findOne({'pivot.value': req.param('value'), "title":req.param('title')}},
function(err, record) {
record.pivot.counter++;
res.redirect(m_pivot.destination);
record.save();
});
});
I solved it temporarily using a simple for loop to parse the object array as follows:
for (var i=0; i <record.pivots.length; i++){
if (record.pivots[i].value == req.param('value')){
res.redirect(record.pivots.destination);
}
}
However, I still think that Mongoose must have a simpler way of interacting with embedded documents - and this loop is somewhat slow, especially when the number of embedded documents grows large.
If anyone has any suggestions for a faster way to search this object array either in js or with a mongoose function, please post below.
the biggest problem with this is that if your req has some fields empty (that should act as wildcard), you will not find anything since mongo tries to match empty params as well, so searching for {"user":"bob", "color":""} is not the same as {"user":"bob", "color":"red"} or {"user":"bob"}. this means that you have to first create a query object and filter out any unused parameters before you pass it in, and if you create a query object, you can no longer do something like "user.name=..." because mongo interperets this as an error since it does not first resolve the object literal into a string.
Any ideas on this problem?
ps. You'd think it would be easy enough to make an object like:
user.name="bob"; user.color:"green"; user.signup.time="12342561"
and then just use user as a query object :/
I think you are looking for the "$in" keyword?
As in:
{a: {$in: [10, "hello"]}}
source: MongoDB Queries CheatSheet