MongoDB Node.js client projection [duplicate] - node.js

This question already has answers here:
projection not working with find query
(2 answers)
Closed 4 years ago.
I know this is probably an obvious question, but I am new to Mongo, and cannot find what I am doing wrong in looking through the documentation and examples... I am trying to query a list of records in mongo pulling out a specific field value from each of them, and I currently have.
const express = require('express');
const MongoClient = require('mongodb').MongoClient;
// Connection URL
const url = 'mongodb://localhost:27017';
// Database Name
const dbName = 'TestDB';
let db = null;
let books = null;
// Use connect method to connect to the server
MongoClient.connect(url, function(err, client) {
if (err) {
console.error("Connection Failed")
}
db = client.db(dbName);
books = db.collection('books')
books.find( {}, { Name:1 } ).toArray().then(console.log)
});
But it prints out
[ { _id: 5b5fae79252d63309c908522,
Name: 'TestBook',
chapters: { '1': [Object] } } ]
Instead of
[ {Name: 'TestBook'} ]

I think you need to provide projection in the options parameter to get only the field name:
books.find({}, { projection: { Name:1 }})
.toArray()
.then(console.log)
Actually, find takes 2 parameters, the first one is the criteria for query and the second one includes some options. You can check the supported fields for options here: http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#find
Updated: For mongodb package version < 3.0. Use fields instead of projection: books.find({}, { fields: { Name:1 }})

Related

Unable to select specific field for MongoDB find operation

I am trying to select only one field from a mongo document and print the value for it. I found this answer https://stackoverflow.com/a/25589150 which showed how we can achieve this. Below I have tried doing the same yet the entire document ends up getting printed.
const mongoHost =
'somemongourl'
const mongodb = require('mongodb');
const { MongoClient } = mongodb;
MongoClient.connect(
mongoHost,
{ useNewUrlParser: true },
async (error, client) => {
if (error) {
return console.log('Unable to connect to database!');
}
const db = client.db('cartDatabase');
const values = await db
.collection('cart')
.find({ customer_key: 'c_1' }, { customer_key: 1, _id: 0 })
.toArray();
console.log(values);
}
);
This is the output for example I got :-
[
{
_id: new ObjectId("611b7d1a848f7e6daba69014"),
customer_key: 'c_1',
products: [ [Object] ],
coupon: '',
discount: 0,
vat: 0,
cart_total: 999.5,
cart_subtotal: 999.5
}
]
This is what I was expecting -
[
{
customer_key: 'c_1'
}
]
The standard Node.js MongoDB driver requires a top-level projection property for the options parameter if you wish to project your documents. This would result in the second parameter of your find() call looking like this:
{ projection: { customer_key: 1, _id: 0 } }
This is indicated in the Node.js MongoDB driver API documentation, which is notably not a 1-to-1 match with the MongoDB shell API.
As of the time of this answer, you could find the collection.find() reference here. This reference shows the following method signature (again as of when this answer was written):
find(filter: Filter<WithId<TSchema>>, options?: FindOptions<Document>)
Following the FindOptions parameter takes us to this reference page, which details the various top-level options properties available for the find() method. Among these is the projection property in question.
In short, don't use the normal MongoDB documentation as a reference for your programming language's MongoDB driver API. There will often be disconnects between the two.

Get table A values with table B where A.field_name = B.field_name [duplicate]

This question already has answers here:
How do I perform the SQL Join equivalent in MongoDB?
(19 answers)
Closed 3 years ago.
In back end I'm using mongoose, express and node js. I want to do joins in mongodb. If this is SQL it's not hard. Since I'm new to mongo database. This is problem to me. I already tried many answers in this platform and none of them help my situation.
I have following two schema in my database.
Item
import mongoose from 'mongoose';
const Schema = mongoose.Schema;
export const item_schema = new Schema({
item_no: {
type: String
},
name: {
type: String
},
item_category: {
type: String
},
no_of_copies: {
type: Number
},
public_or_rare: {
type: String
},
user_no: {
type: String
}
});
Book
import mongoose from 'mongoose';
const Schema = mongoose.Schema;
export const book_schema = new Schema({
item_no: {
type: String
},
isbn_no: {
type: String
},
author: {
type: String
},
published_year: {
type: Number
},
publisher: {
type: String
},
book_category: {
type: String
}
});
Note that there is no error in these models because those runs well with other controllers in my API
I want to get book and item tables data as one object where book and item share same item_no
In order to achieve my aim so far I tried following code,
export const get_books_all_details = (req, res) => {
Book.find({}, (err, book) => {
if (err) {
res.send(err);
}
else {
let my_book = book;
// res.json(my_book);
Item.findOne({ item_no: my_book.item_no }, (err, item) => {
//Item.find({}, (err, item) => {
if (err) {
res.send(err);
}
else {
let my_item = item;
//res.send(my_book+my_item);
res.json({
/* item_no: my_item.item_no,
item_name: my_item.item_name,
item_category: my_item.item_category,
no_of_copies: my_item.no_of_copies,
public_or_rare: my_item.public_or_rare,
isbn_no: my_book.isbn_no,
author: my_book.author,
published_year: my_book.published_year,
publisher: my_book.publisher,
book_category: my_book.book_category , */
book:my_book,
item:my_item
})
}
});
}
});
};
In top I use find() to get all books and if there is record in item table which matches item_no I want to get that particular item too. That's why I used findOne() inside find()
I don't know is it right or wrong !
So this new guy wait for you guys help and really appreciate it. If you could help me with code and explanations that will be great !
I want to do joins in mongodb
Just don't. MongoDB is a NoSQL database, specifically built to avoid joins and to enforce denormalization of data. If you need to join a document, put it inside of another document. If you build your collections in MongoDB like you do in any SQL database, you'd just have a non ACID compliant relational database, which is dangerous.

How to watch for changes to specific fields in MongoDB change stream

I am using the node driver for mongodb to initiate a change stream on a document that has lots of fields that update continuously (via some logic on the insert/update end that calls $set with only the fields that changed), but I would like to watch only for changes to a specific field. My current attempt at this is below but I just get every update even if the field isn't part of the update.
I think the "updateDescription.updatedFields" is what I am after but the code I have so far just gives me all the updates.
What would the proper $match filter look like to achieve something like this? I thought maybe checking if it's $gte:1 might be a hack to get it to work but I still just get every update. I've tried $inc to see if the field name is in "updatedFields" as well but that didn't seem to work either.
const MongoClient = require('mongodb').MongoClient;
const uri = 'mongodb://localhost:27017/?replicaSet=rs0';
MongoClient.connect(uri, function(err, client) {
const db = client.db('mydb');
// Connect using MongoClient
var filter = {
$match: {
"updateDescription.updatedFields.SomeFieldA": { $gte : 1 },
operationType: 'update'
}
};
var options = { fullDocument: 'updateLookup' };
db.collection('somecollection').watch(filter, options).on('change', data => {
console.log(new Date(), data);
});
});
So i figured this out...
For anyone else interested: My "pipeline" (filter, in my example) needs to be an array
this works...
const MongoClient = require('mongodb').MongoClient;
const uri = 'mongodb://localhost:27017/?replicaSet=rs0';
MongoClient.connect(uri, function(err, client) {
const db = client.db('mydb');
// Connect using MongoClient
var filter = [{
$match: {
$and: [
{ "updateDescription.updatedFields.SomeFieldA": { $exists: true } },
{ operationType: "update" }]
}
}];
var options = { fullDocument: 'updateLookup' };
db.collection('somecollection').watch(filter, options).on('change', data =>
{
console.log(new Date(), data);
});
});
I'm looking for something similar, but from the blog post at https://www.mongodb.com/blog/post/an-introduction-to-change-streams, it looks like you might need to change your filter to:
var filter = {
$match: {
$and: [
{ "updateDescription.updatedFields.SomeFieldA": { $exists: true } },
{ operationType: 'update'}
]
}
};

how to properly retrieve mongodb data using node / mongoose [duplicate]

This question already has answers here:
Mongoose always returning an empty array NodeJS
(7 answers)
Closed 5 years ago.
i am working upon mongoose to list all the data from a collection in a db in mongodb:
from the requests:
http://localhost:3000/listdoc?model=Organization
i am doing the following code :
exports.listDoc = function(req, res) {
var Model = mongoose.model(req.query.model); //This is defined and returns my desired model name
Model.find().populate('name').exec(function(err, models) {
if (err) {
res.render('error', {
status: 500
});
} else {
res.jsonp(models);
}
});
};
I already have my entry in database
But the above code returns empty. Why?
EDIT : the following code also returns empty:
exports.listDoc = function(req, res) {
var Model = mongoose.model(req.query.model);
Model.find({},function(err,models){
console.log(models);
if (err) {
res.render('error', {
status: 500
});
} else {
res.jsonp(models);
}
});
};
schema used :
var Organization = mongoose.Schema({
name: String
});
Your problem is mongoose pluralizes collections. Mongoose is querying "organizations" but your data is in mongodb as "organization". Make them match and you should be good to go. You can either rename it in mongodb via the mongo shell or tell mongoose about it. From the mongoose docs:
var schema = new Schema({ name: String }, { collection: 'actor' });
// or
schema.set('collection', 'actor');
// or
var collectionName = 'actor'
var M = mongoose.model('Actor', schema, collectionName)
From official doc
Population is the process of automatically replacing the specified
paths in the document with document(s) from other collection(s).
Try it without populate
Model.find({}).exec(function(err, models) {
if (err) {
res.render('error', {
status: 500
});
} else {
res.json(models);
}
});

NodeJS + MongoDB: Getting data from collection with findOne ()

I have a collection "companies" with several objects. Every object has "_id" parameter. I'm trying to get this parameter from db:
app.get('/companies/:id',function(req,res){
db.collection("companies",function(err,collection){
console.log(req.params.id);
collection.findOne({_id: req.params.id},function(err, doc) {
if (doc){
console.log(doc._id);
} else {
console.log('no data for this company');
}
});
});
});
So, I request companies/4fcfd7f246e1464d05000001 (4fcfd7f246e1464d05000001 is _id-parma of a object I need) and findOne returns nothing, that' why console.log('no data for this company'); executes.
I'm absolutely sure that I have an object with _id="4fcfd7f246e1464d05000001". What I'm doing wrong? Thanks!
However, I've just noticed that id is not a typical string field. That's what mViewer shows:
"_id": {
"$oid": "4fcfd7f246e1464d05000001"
},
Seems to be strange a bit...
You need to construct the ObjectID and not pass it in as a string. Something like this should work:
var BSON = require('mongodb').BSONPure;
var obj_id = BSON.ObjectID.createFromHexString("4fcfd7f246e1464d05000001");
Then, try using that in your find/findOne.
Edit: As pointed out by Ohad in the comments (thanks Ohad!), you can also use:
new require('mongodb').ObjectID(req.params.id)
Instead of createFromHexString as outlined above.
That's because _id field in mongo isn't of string type (as your req.params.id). As suggested in other answers, you should explicitly convert it.
Try mongoskin, you could use it like node-mongodb-native driver, but with some sugar. For example:
// connect easier
var db = require('mongoskin').mongo.db('localhost:27017/testdb?auto_reconnect');
// collections
var companies = db.collection('companies');
// create object IDs
var oid = db.companies.id(req.params.id);
// some nice functions…
companies.findById();
//… and bindings
db.bind('companies', {
top10: function(callback) {
this.find({}, {limit: 10, sort: [['rating', -1]]).toArray(callback);
}
});
db.companies.top10(printTop10);
You can use findById() which will take care of the id conversion for you.
company = Company.findById(req.params.id, function(err, company) {
//////////
});
In case these didn't work for you, this worked for me for accessing a blog post:
const getSinglePost = async (req, res) => {
let id = req.params.id;
var ObjectId = require('mongodb').ObjectId;
const db = await client.db('CMS');
const data = await db.collection("posts").findOne({ _id: ObjectId(id) })
if (data) {
res.status(200).send(data)
} else res.status(400).send({ message: "no post found" })
}

Resources