Mongodb not returning specific fields - node.js

I am trying to return only one field sessions from a document.
I'm using the current query (it returns the entire document):
yield users.findOne({
'_id': id // var id holds object id ObjectId("560ae1dc53cb3222679430f1")
}, {
'_id': 0, // <--- being ignored
'sessions': 1 // <--- being ignored
});
I tried in mongo shell and this works as it should:
db.users.find({"_id":ObjectId("560ae1dc53cb3222679430f1")},{"sessions":1,"_id":0}).pretty() // <--- works
I'm currently using co-monk which is based off of mongoskin. So it should work.

Not made clear in the documentation, but there is an explicit key name syntax to the "options" object :
yield users.findOne({ '_id': id }, { 'fields': { '_id': 0, 'sessions': 1 }});
So it works a bit differently to the MongoDB shell API. The same applies for other options such as sort.

The accepted answer didn't work in my case, so I went digging through the docs and this is what I found for the fields option: Deprecated Use options.projection instead, and got the respective warning in the console. Chaining in .project() as with .find() didn't work for .findOne() in my case, so it has to be in the options using projection:
yield users.findOne({
'_id': id
}, { projection: { //projection rather than fields
'_id': 0,
'sessions': 1 }
});
Here it is: mongodb.github.io/node-mongodb-native

2022 update
You have to use projection in latest update.
Reference:
https://www.mongodb.com/docs/drivers/node/current/quick-reference/
Here is a sample code for this question.
const ObjectId = require('mongodb').ObjectId;
var query = { _id: ObjectId('your search object id here') };
var options = { projection: { sessions: 1, _id: 0 } };
users.findOne(query, options);

Related

Nodejs Express find by id and check other id exist in array or not

I Need to find data by its and check that if in that Id there is no of arrays in which object Ids are saved need to match that also.
I try like this
const exists = await Partners.find({ '_id': req.params.id, partnerLikeuser: { $elemMatch: { $eq: req.user.partner_id } } },);
But its not working I need to find data by id in which partnerLikeuser array have req.user.partner_id
Not sure the best method but You can find like this. It will check _id and partnerLikeuser both.
const exists = await Partners.find({ '_id': req.params.id, partnerLikeuser: req.user.partner_id },);

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.

Mongoose: how to check if document is modified via model.findOneAndUpdate()

In mongoose, we can check if an update operation has modified the document with model.update():
model.update(query, update, function(err, raw){
if (raw.nModified >= 1) console.log('document is modified!')
});
Is there a way to do the same with model.findOneAndUpdate()?
model.findOneAndUpdate(query, update, { new: true }, function(err, doc){
if (doc) {
// So MongoDB found the document, but is there a way
// to know the document was indeed modified?
}
});
You can pass the option { passRawResult : true } to mongoose to advice mongoose to pass the raw result of the underlying mongodb driver, in this case mongodb-native, as a third argument to the callback.
mongodb-native documentation for findOneAndUpdate
model.findOneAndUpdate(query, update, { new: true, passRawResult : true }, function(err, doc, res){
// res will look like
// { value: { _id: 56a9fc80a7f9a4d41c344852, name: 'hugo updated', __v: 0 },
// lastErrorObject: { updatedExisting: true, n: 1 },
// ok: 1 }
});
In case the update did not succeed due to no matching document was found a null res will be passed to the callback. In case a document matched but field values where the same as before the update res object will not give you enough information to figure out if values were updated for the matching document.

How to properly do a Bulk upsert/update in MongoDB

I'm trying to:
Find a document according to a search criteria,
If found, update some attributes
If not insert a document with some attributes.
I'm using a Bulk.unOrderedOperation as I'm also performing a single insert. And I want to do everything in one operation againast DB.
However something it's causing nothing is being inserted for the update/upsert operation.
This is the insert document:
var lineUpPointsRoundRecord = {
lineupId: lineup.id, // String
totalPoints: roundPoints, // Number
teamId: lineup.team, // String
teamName: home.team.name, // String
userId: home.iduser, // String
userName: home.user.name, // String
round: lineup.matchDate.round, // Number
date: new Date()
}
This is the upsert document:
var lineUpPointsGeneralRecord = {
teamId: lineup.team, // String
teamName: home.team.name, // String
userId: home.iduser, // String
userName: home.user.name, // String
round: 0,
signupPoints: home.signupPoints, // String
lfPoints: roundPoints+home.signupPoints, // Number
roundPoints: [roundPoints] // Number
};
This is how I'm trying to upsert/update:
var batch = collection.initializeUnorderedBulkOp();
batch.insert(lineUpPointsRoundRecord);
batch.find({team: lineUpPointsRoundRecord.teamId, round: 0}).
upsert().
update({
$setOnInsert: lineUpPointsGeneralRecord,
$inc: {lfPoints: roundPoints},
$push: {roundPoints: roundPoints}
});
batch.execute(function (err, result) {
return cb(err,result);
});
Why wouldn't it be upserting/updating?
Note
That is JS code using waterline ORM which also uses mongodb native driver.
Your syntax here is basically correct, but your general execution was wrong and you should have "seperated" the "upsert" action from the other modifications. These will otherwise "clash" and produce an error when an "upsert" occurs:
LineupPointsRecord.native(function (err,collection) {
var bulk = collection.initializeOrderedBulkOp();
// Match and update only. Do not attempt upsert
bulk.find({
"teamId": lineUpPointsGeneralRecord.teamId,
"round": 0
}).updateOne({
"$inc": { "lfPoints": roundPoints },
"$push": { "roundPoints": roundPoints }
});
// Attempt upsert with $setOnInsert only
bulk.find({
"teamId": lineUpPointsGeneralRecord.teamId,
"round": 0
}).upsert().updateOne({
"$setOnInsert": lineUpPointsGeneralRecord
});
bulk.execute(function (err,updateResult) {
sails.log.debug(err,updateResult);
});
});
Make sure your sails-mongo is a latest version supporting the Bulk operations properly be the inclusion of a recent node native driver. The most recent supports the v2 driver, which is fine for this.
I recommend use bulkWrite exemplary code with bulk upsert of many documents:
In this case you will create documents with unique md5. If document exists then will be updated but no new document is created like in classical insertMany.
const collection = context.services.get("mongodb-atlas").db("master").collection("fb_posts");
return collection.bulkWrite(
posts.map(p => {
return { updateOne:
{
filter: { md5: p.md5 },
update: {$set: p},
upsert : true
}
}
}
),
{ ordered : false }
);
https://docs.mongodb.com/manual/reference/method/db.collection.bulkWrite/
Typically I have always set upsert as a property on update. Also update should be able to find the record itself so no need to find it individually.
Depending on the environment the $ may or may not be necessary.
batch.update(
{team: lineUpPointsRoundRecord.teamId, round: 0},
{
$setOnInsert: lineUpPointsGeneralRecord,
$inc: {lfPoints: roundPoints},
$push: {roundPoints: roundPoints},
$upsert: true
});

Mongoose: Get doc _id after upsert

is there any way to get the record _id after an upsert?
I've seen this post (How to insert a doc into mongodb using mongoose and get the generated id?), but this is oriented only to inserts, not updates.
Also, using the MongoDB you can use get the _id using getlasterror (https://groups.google.com/forum/?fromgroups=#!topic/mongoose-orm/ehZ11QY-OUw), but Mongoose doesn't provides access to it (https://groups.google.com/forum/?fromgroups=#!topic/mongoose-orm/pSv6WrasvWg)
Thanks
Use Mongoose's findOneAndUpdate method with upsert: true in the options object.
var query = { name: 'borne' },
data = { name: 'jason borne' },
options = { upsert: true };
Model.findOneAndUpdate(query, data, options, function (err, object) {
/* use object._id */
});
Another possibility with promises:
Model.findOneAndUpdate(query, data, options, function (err, object) {
})).then((result) => {
/* return result.upserted[0]._id */
})
...where result is the following:
{ n: 1,
nModified: 0,
upserted: [ { index: 0, _id: /* some id */ } ],
ok: 1 }
If you want the updated document returned, and in cases where it didn't exist and was upserted the new document. Below is the option you need to set.
set new: true to the options: options = { upsert: true, new: true };
Source: Based on Jamiel's comment, I am adding his comment as an answer as it was hard time finding for me to get that _id when no document existed and created by upsert (And I was trying to create my own extended method).

Resources