MongoDB updating embedded document isn't working - node.js

I'm trying to update embedded document, but it is not working. This is what documents look like:
{
"_id" : ObjectId("577c71735d35de6371388efc"),
"category" : "A",
"title" : "Test",
"content" : "Test",
"tags" : "test",
"comments" : [
{
"_id" : ObjectId("57811681010bd12923eda0ca"),
"author" : "creator",
"email" : "creator#example.com",
"text" : "helloworld!"
},
{
"_id" : ObjectId("57811b17b667676126bde94e"),
"author" : "creator",
"email" : "creator#example.com",
"text" : "helloworld2!"
}
],
"createdAt" : ...,
"updatedAt" : ...
}
you can see the comments field is embedded document that contains comments. I want to update specific comment, so I made query like this(node.js):
db.update('posts', {
_id: new ObjectID(postId), // ID of the post
comments: {
$elemMatch: {
_id: new ObjectId(commentId)
}
}
}, {
$set: {
"comments.$.author": newComment.author,
"comments.$.email": newComment.email,
"comments.$.text": newComment.text,
"comments.$.updatedAt": new Date()
}
}) ...
when I run this query, no error was shown but update wasn't applied. I tried this query too:
{
_id: new ObjectId(postId),
"comments._id": new ObjectId(commentId)
}
but not worked either. Am I missing something? I'm using Mongo v3.2.7.

Please try the below code. I think the "ObjectId" (i.e. case) should be the problem. Just check how you defined the object id and keep it consistent in the two places that you have used (i.e. posts _id and comments _id -> both places).
ObjectID = require('mongodb').ObjectID
The below code works fine for me. Basically, your query seems to be correct.
var Db = require('mongodb').Db, MongoClient = require('mongodb').MongoClient, Server = require('mongodb').Server, ReplSetServers = require('mongodb').ReplSetServers, ObjectID = require('mongodb').ObjectID, Binary = require('mongodb').Binary, GridStore = require('mongodb').GridStore, Grid = require('mongodb').Grid, Code = require('mongodb').Code, assert = require('assert');
var db = new Db('localhost', new Server('localhost', 27017));
db.open(function(err, db) {
var collection = db.collection("posts");
var postId = '577c71735d35de6371388efc';
var commentId = '57811681010bd12923eda0ca';
var query = {
_id : new ObjectID(postId),
comments : {
$elemMatch : {
_id : new ObjectID(commentId)
}
}
};
collection.update(query, {
$set : {
"comments.$.author" : "new author",
"comments.$.email" : "newemail#gmail.com",
"comments.$.text" : "new email updated",
"comments.$.updatedAt" : new Date()
}
}, {
multi : false
}, function(err, item) {
assert.equal(null, err);
console.log("comments updated ..." + JSON.stringify(item));
});
});

Related

Mongodb DB query to compare the data from two collections and get the results if data is same

I have two collections data like below . I need compare the two collections data and get the data if the data is same . Tried with below query but is it not giving any results .I am new to mongodb query ,Can anyone help me how to get the code key values if the data is same in both collections .The query is not returning any errors but the code values are not getting populated to new cllection
**Collection 1:**
{
"_id" : {
"value" : "12345"
},
"value" : {
"Identifier" : "12345",
"statu" : "simple",
"code" : {
"key" : "US",
"value" : "United State of America"
},
"Code" : {
"key" : "UK",
"value" : "London"
}
}
**Collection 2** :
{
"_id" : ObjectId("12345"),
"value" : {
"Identifier" : "12345",
"statu" : "simple",
"code" : {
"key" : "US",
"value" : "United State of America"
},
"Code" : {
"key" : "UK",
"value" : "London"
}
},
}
Mongo DB :
var identifiers = db.getSiblingDB("Datbase").getCollection("Collection1").find({
$or:[
{'code':{$exists:true}},
{'Code1':{$exists:true}},
]
}).toArray()
var bulk = db.getSiblingDB("Database2").getCollection("Collection2").initializeUnorderedBulkOp()
identifiers.forEach(Identifier =>{
db.getSiblingDB("Database2").getCollection("Collection2").aggregate([
{
$match:{
"Identifier":'$Identifier',
}
},
{
"$group" : {
"_id" : {
"Identifier":'$Identifier',
"key" : "$code.key",
"value" : "$code.value",
"key1" : "$code1.key1",
"value1" : "$code1.value2",
}
}
}, {
$merge:{
into:{
db:'Database',
coll:'Collection'
}
}
}
])
})
Using cursor get one by one items from 1st collection
For every item from 1st collection query 2nd collection for existense
If item does not exist or it's body is different (Use lodash.isEqual method) push them to some array or use replaceOne method to insert or replace document. (install lodash: npm i --save lodash)
const _ = require('lodash'); // import it at top
(async () => { // You can remove it if Your code already inside async scope
const source = db.getSiblingDB("Datbase").getCollection("Collection1");
const destination = db.getSiblingDB("Datbase").getCollection("Collection2");
const query = {$or:[
{'code':{$exists:true}},
{'Code1':{$exists:true}},
]};
const cursor = await source.find(query);
const differentItems = [];
// iterating source collection items
while(await cursor.hasNext()) {
const src = await cursor.next(); // source collectio inem
const queryDestination = {
"Identifier": src.Identifier, // extend Your equality constrains here
};
const dest = await destination.findOne(queryDestination);
// it may not exist || may be different (not equal)
const isDifferent = !dest || !(
_.isEqual(
_.omit(src, ['_id']),
_.omit(dest, ['_id'])
)
);
if (isDifferent) {
differentItems.push({src, dest});
/* or replace in db
await destination.replaceOne(
queryDestination,
_.omit(src, ['_id']),
{
upsert: true,
}
);
*/
}
}
console.log(`found ${differentItems.length} different documments`);
console.log(JSON.stringify(differentItems, null, 4));
)();

How do i retrieve just the child-object in Azure Cosmos using mongoose and Node.js?

I am using Azure cosmos db with the Mongodb API. Also i am using mongoose to create schemas and create new documents in the database. I am also using Node.js.
At this point I am considering using a One-to-Many relationship with embedded documents.
The data structure is like this :
{
"_id" : "locality1",
"_type" : "Locality",
"name" : "Wallmart",
"subsectionList" : [
{
"_id" : "subsection1",
"_type" : "SubSection",
"name" : "First floor",
"sensorList" : [
{
"_id" : "sensor1",
"_type" : "Sensor",
"placement" : "In the hallway"
},
{
"_id" : "sensor2",
"_type" : "Sensor",
"placement" : "In the ceiling"
}
]
},
{
"_id" : "subsection2",
"_type" : "SubSection",
"name" : "Second floor",
"sensorList" : [ ],
}
],
}
I want to retrieve ONLY the "sensor1"-object, not anything from the parent.
Using querying i am only able to retrieve the entire "locality1"-object, with all its underlying subsections and sensors. On a larger scale that is an unnecessary large amount of data.
Here is my query so far.
Locality.find().where('subsectionList.sensorList._id').equals("sensor1").then(doc => {
console.log(doc)
})
I appreciate any tips! :)
Based on my test, i can't get rid of the _id property anyway even though i followed the parameters which is mentioned here.
Locality.find({},'subsectionList', function (err, locas)
The above query still return the results including _id property.(It seems a default item)
I get a workaround from this blog that you could loop the array to filter your desired columns.
var mongoose = require('mongoose');
var COSMOSDB_CONNSTR= "mongodb://***.documents.azure.com:10255/db";
var COSMODDB_USER= "***";
var COSMOSDB_PASSWORD= "***";
mongoose.connect(COSMOSDB_CONNSTR+"?ssl=true&replicaSet=globaldb", {
auth: {
user: COSMODDB_USER,
password: COSMOSDB_PASSWORD
}
}).then(() => console.log('Connection to CosmosDB successful'))
.catch((err) => console.error(err));
const Locality = mongoose.model('Locality', new mongoose.Schema({
_id: String,
subsectionList: [{
sensorList: [{
_id: String,
_type: String,
placement: String
}]
}]
}));
Locality.find({},'subsectionList', function (err, locas) {
if (err) return handleError(err);
var returnArray = [];
for(var i = 0; i<locas.length;i++){
for(var j = 0; j<locas[i].subsectionList.length;j++){
for(var k = 0; k<locas[i].subsectionList[j].sensorList.length;k++){
if(locas[i].subsectionList[j].sensorList[k]._id == 'sensor1')
returnArray.push(locas[i].subsectionList[j].sensorList[k]);
}
}
}
console.log(returnArray);
});

How can append data to a field in mongodb and node.js

In this data in mongodb i want to update user by _id.
{
"_id" : ObjectId("aaaab51b080ddbaaaa2db6da"),
"user" : "1111",
}
{
"_id" : ObjectId("aaaab564ef9aaaa640adf2a9"),
"user" : "2222"
}
But i want this output:
{
"_id" : ObjectId("aaaab51b080ddbaaaa2db6da"),
"user" : "1111",
}
{
"_id" : ObjectId("aaaab564ef9aaaa640adf2a9"),
"user" : "2222Helooword" //user + "Helooword"
}
I mean user +"Helooword". I want append "Helooword" to user.
I use this code but it dose not work.
I want to use ONE query .(findOneAndUpdate)
var ObjectID = require('mongodb').ObjectID;
var o_id = new ObjectID("aaaab564ef9aaaa640adf2a9");
array.findOneAndUpdate
(
{ '_id' : o_id },
{$set:{ user:['$user','Helooword']}}, //output:"user":"$user,heeeeeeeeo",
function (error, success)
{
if (error) console.log(error);
if(success == null )
console.log("nullllllllllllllllllllllll");
console.log(success);
}
);
For now, the answer is you can't do this in a findOneAndUpdate.
See this question for other options/ideas.

How to push an object to Array in Mongo using Node driver

I am learning MongoDB and Node and trying to make a crud application without any ORM such as Mongoose.
I am facing an issue inserting an object to an array which is part of a document.
Basically I want to add an "order" to the orders attribute of "product" document each time a user buys a product.
console.log(req.session.cartitems);
console.log(req.session.cartqty);
for(item in req.session.cartitems)
{
console.log(req.session.cartitems[item]);
var orderedItem = req.session.cartitems[item];
mongo.connect(mongoURL, function(){
console.log('Connected to mongo at: ' + mongoURL);
var coll = mongo.collection('products');
coll.update({_id:orderedItem._id},{
$push: {
orders: {
buyer: req.session.username,
quantity:orderedItem.item_quantity
}
}
});
});
}
but the update operation is not doing anything.
Here is a sample object inside Mongo that I am trying to push to:
{
"_id" : ObjectId("5810a2b01ef60d0cdcc6e80c"),
"product_id" : 1,
"item_name" : "FitBit Charge 2",
"item_description" : "Charge HR + PurePulse Monitor",
"seller_name" : "ak#gmail.com",
"item_price" : "150",
"item_quantity" : "10",
"sale_type" : "sale",
"posted_at" : "2016:10:26 05:33:52",
"expires_at" : "2016:10:30 05:33:52",
"bids" : [],
"orders" : []
}

Querying Embedded Documents with NodeJS and Mongoose

I need to query the following data from mongodb:
Project has many Regions, a Region has many Links
Here's the data:
{ "_id" : ObjectId( "4f26a74f9416090000000003" ),
"description" : "A Test Project",
"regions" : [
{ "title" : "North America",
"_id" : ObjectId( "4f26a74f9416090000000004" ),
"links" : [
{ "title" : "A Really Cool Link" } ] },
{ "description" : "That Asia Place",
"title" : "Asia",
"_id" : ObjectId( "4f26b7283378ab0000000003" ),
"links" : [] },
{ "description" : "That South America Place",
"title" : "South America",
"_id" : ObjectId( "4f26e46b53f2f90000000003" ),
"links" : [] },
{ "description" : "That Australia Place",
"title" : "Australia",
"_id" : ObjectId( "4f26ea504fb2210000000003" ),
"links" : [] } ],
"title" : "Test" }
Here's my model setup:
// mongoose
var Link = new Schema({
title : String
, href : String
, description : String
});
var Region = new Schema({
title : String
, description : String
, links : [Link]
});
var Project = new Schema({
title : String
, description : String
, regions : [Region]
});
mongoose.model('Link', Link);
mongoose.model('Region', Region);
mongoose.model('Project', Project);
var Link = mongoose.model('Link');
var Region = mongoose.model('Region');
var Project = mongoose.model('Project');
The query that I'm struggling with is returning a single region object matched on ID. I'm fine returning all of the regions with all of their respective links, but limiting it to the ID of just one region has been a problem.
Here's my broken route that I'm working with:
app.get('/projects/:id/regions/:region_id', function(req, res){
Project.findById(req.param('id'), function(err, project) {
if (!err) {
project.regions.findById(req.params.region_id, function(err, region) {
if (!err) {
res.render('project_regions', {
locals: {
title: project.title,
project: project
}
});
}
});
} else {
res.redirect('/')
}
});
});
I know the above will not work because the object returned by "findById" does not respond to findByID, but it illustrates what I'm trying to do. I tried doing a custom query, but it always returned the entire document, not the single Region that I wanted.
I also tried querying directly off the Region Schema, but that is not returning any results. I assume to query from a Schema that's a subdocument I would have to contextually provide what the parent document is.
In other words, the following does not return an "region" object with data:
app.get('/projects/:id/regions/:region_id', function(req, res){
Region.findById(req.params.region_id, function(err, region) {
if (!err) {
res.render('project_regions_show', {
locals: {
title: "test",
region: region
}
});
} else {
res.redirect('/')
}
});
});
Appreciate any help.
bstar,
You can prevent sub documents from loading by using the query.select:
ie.
Entity.find({ ... })
.select({childentities: 0}) //excludes childentities
.exec(function(err, entities){
...
res.json({entities: entities});
});
I'd recommend extracting the regions into a separate collection with a "projectId: ObjectId()" field. That may give you the querying flexibility you're looking for.

Resources