Mongodb delete subdocument - javascript

I'm trying to delete a subdocument in mongoDb but can't succeed in it. I've tried with $update,$push and $pull but I'm not successful.
I have the following document:
db.users.findOne({"_id": ObjectId("545677a9e4b0e0ef9379993c")})
{
"_class" : "com.xxx.xxx.server.da.User",
"_id" : ObjectId("545677a9e4b0e0ef9379993c"),
"bookSummaries" : [
{
"_id" : ObjectId("545677e7e4b0e0ef9379993d"),
"isbn" : "2746969644"
"title": "test title"
},
{
"_id" : ObjectId("546a522a44ae4f5e652fdca7"),
"loanSummaries" : [
{
"loanStatus" : "REQUESTED",
"loanId" : "5473992044aec466a619290c"
},
{
"loanStatus" : "REQUESTED",
"loanId" : "5473997d44aec466a619290d"
},
{
"loanStatus" : "REQUESTED",
"loanId" : "547605a744ae0f0d558ae757"
}
],
"testArray" : [
{
"title" : "Back to the future",
"id" : "test"
},
{
"title" : "Back to the future",
"id" : "test2"
},
{
"title" : "Back to the future",
"id" : "test3"
},
"test ",
"test ",
"test 2",
"test 2",
{
"loanStatus" : "REQUESTED"
}
],
"title" : "Back to the future"
}
]
}
and I'm trying to create the queries to:
delete the whole "testArray" subdocument for only this specific subdocument
delete a specific loanSummaries give its loanId for this specific subdocument
Can you help me creating those queries? I've seen several post like this one, but it is not the same problem.
Thanks a lot

I recently had the same problem where I had to remove a nested subarray. In the query you need to identify the exact object that you want to remove, and then in your update query you can use the $ sign as index for the object in the array that you want to pull.
var query = {
"_id" : ObjectId(someUserId),
"bookSummaries._id" : ObjectId(bookId), //might also work with isbn as long as it is uniq
"bookSummaries.loanSummaries.loanId" : loanId
};
var updateQuery = {
"$pull" : {
"bookSummaries.$.loanSummaries" : {
"loanId": loadId
}
}
}
Update
I tried the following queries in my shell which worked fine. You will have to enter the appropirate ids.
var query = { "_id" : ObjectId("53b73b1108fe927c0e00007f"), "bookSummaries._id" : ObjectId("53b73b1108fe927c0e00007f"), "bookSummaries.loanSummaries.loanId" : "53b73b1108fe927c0e00007f" }
var updateQuery = { "$pull" : { "bookSummaries.$.loanSummaries" : { "loanId": "53b73b1108fe927c0e00007f" } } }
Update 2
If you already know the index of item/object you want to remove you can use the queries below in order to achieve this.
Find the document you want to edit
var query = {
"_id" : ObjectId(someUserId),
};
Unset the object you want to remove
var update1 = {
"$unset" : {
"bookSummaries.1.loanSummaries.2" : 1
}
}
Pull the object which has the value null.
var update2 = {
"$pull" : {
"bookSummaries.1.loanSummaries" : null
}
}
And to remove you can basically use the same queries.
Find the document you want to edit
var query = {
"_id" : ObjectId(someUserId),
};
Unset the object you want to remove
var update1 = {
"$unset" : {
"bookSummaries.0.testArray" : 1
}
}

Because MongoDB provides a full JavaScript environment you can easily manipulate the document and save the data back to the db.
*Note: if you are using MongoDB with php or python etc. there are equivalent ways to do that.
1.to delete whole "testArray" subdocument for only this specific subdocument for example index(1) do
db.users.find({"_id": ObjectId("545677a9e4b0e0ef9379993c")}).forEach(function (user) {
delete user.bookSummaries[1].testArray;
//Saveing the changes
db.users.save(user);
});
to delete a specific loanSummaries give its loanId for this specific subdocument for example id 5473992044aec466a619290c do
db.users.find({"_id": ObjectId("545677a9e4b0e0ef9379993c")}).forEach(function (user) {
var loanToDelete = "5473992044aec466a619290c";
var loanIndexToDelete = -1;
var i;
for(i in user.bookSummaries[1].loanSummaries) {
if(user.bookSummaries[1].loanSummaries[i].loanId === loanToDelete) {
loanIndexToDelete = i;
break;
}
}
if (loanIndexToDelete > -1) {
delete user.bookSummaries[1].loanSummaries[loanIndexToDelete];
}
//Saving the changes
db.users.save(users);
});

I had to do something similar but delete multiple subdocuments instead of just one. My query included an array of ids and this worked for me:
User.updateOne(
{ _id: userId },
{
$pull: { bookSummaries: { _id: { $in: ids } } },
});

Related

Check if item value exists in Firebase array

{
"accounts" : {
"-account1" : {
"email" : "test#example.com",
"name" : "John doe",
"online" : false,
"profilePic" : "example.com/img.png",
"username" : "jonh_doe"
"tokens" : [
"token11111",
"token22222",
"token33333"]
},
"-account2" : {
"email" : "testymctest#example.com",
"name" : "Jane doe",
"online" : false,
"profilePic" : "example.com/img.png",
"username" : "jane"
"tokens" : [
"token44444",
"token55555",
"token66666"]
}
}
}
My user data is structured as above and I'm trying to determine if -account1 has a token with the value "token11111"
Other Firebase examples suggest using snapshot, but I haven't found an example that drills down into a child element to find a value.
This is what I've tried
firebase.database().ref('accounts/-account1/tokens')
.equalTo(newToken)
.once('value')
.then(function(tokens) {
if (tokens.exists()) {
//Token already exists
}
else{
//Push new token to db
}
});
When you get an array-like object back from a Firebase snapshot (the keys are numbers starting a 0), you deal with it just like a regular JavaScript array:
var ref = firebase.database().ref('/accounts/-account1/tokens');
ref.once('value').then(function(snap) {
var array = snap.val();
for (var i in array) {
var value = array[i]
console.log(value);
if (value == 'whatever') { ... }
}
});
This will iterate and print each value. You can look for any value that you like in that loop. Or you can includes(x) on the array in JavaScript ES2016.

MongoDB- Return Array of existing fields by compare collection with Array of object

I'm new to Mongo and trying compare a array with a documents of collections and return list of matching records.
Let me explain:First Array
I have a collection (user) with following documents:
> db.user.find().pretty()
{
"_id" : ObjectId("57358220bf3e7d076b6ccdb1"),
"name" : "Sunny",
"phone" : "9417702107",
"email" : "ssdhiman07#gmail.com"
}
{
"_id" : ObjectId("57358242bf3e7d076b6ccdb2"),
"name" : "Pal",
"phone" : "9015719419",
"email" : "ss998#gmail.com"
}
{
"_id" : ObjectId("57358262bf3e7d076b6ccdb3"),
"name" : "viveky",
"phone" : "8826565107",
"email" : "sds998#gmail.com"
}
Second Array: i have a array of objects that is come from Http request below is structure of array.
{
"contacts" : [
{
"name" : "Sunny",
"phone" : "9417702107"
},
{
"name" : "Sukhpal",
"phone" : "9015719419"
},
{
"name" : "anurag",
"phone" : "9988776655"
},
{
"name" : "vivek",
"phone" : "8826565107"
}
]
}
Now I want to know which objects of Second Array are exists in First Array and which doesn't . Comparison should on basis of phone only . And in result i want same Array as Second Array but with one extra field that is
"exists":"true" or "exists":"false" . Something like this.
{
"contacts" : [
{
"name" : "Sunny",
"phone" : "9417702107"
"exists" :"true"
},
{
"name" : "pal",
"phone" : "90177668899"
"exists" :"false"
}
]
}
So for this i had tried something here is code of node.js with mongoos.
exports.matchcontacts = function(req, res, next)
{
var response = {};
var conArray = req.body.contacts;
var contact_list = [];
for(var i=0; i<conArray.length;i++)
{
var name = conArray[i].name;
var phone = conArray[i].phone;
Users.findOne({"phone":conArray[i].phone},function(err,data)
{
if(err)
{
response = {"error" : true,"message" : "Error fetching data"};
}
else if(!data)
{
contact_list.push({name:name,phone:phone,exists:"false"});
}
else
{
contact_list.push({name:name,phone:phone,exists:"true"});
}
});
}
response = {"error":false,"contacts":contact_list};
res.json(response);
};
But always got null {} empty result, and if i tried to get response inside Callback function then it return only single last compared value.
Problem is in first method is that callback function return result very late so result always empty .
and in second method loop override result and it also inefficient to use callback inside loop it will call no of time. So whole story i had explained
Now Please can anybody help me with code or suggest right way to get desired result thanks
HavenĀ“t used mongodb, but the idea I would use is to first iterate your contacts and make a mapping of the phones to the corresponding object and mark them as non existent:
var obj = {};
for(var i=0; i<conArray.length;i++){
obj[conArray[i].phone] = conArray[i];
conArray[i].exists = false;
}
Then search in some way for the users that have those phones in your db, something like
var results = Users.find(records that have phone in Object.keys(obj) array)
Finally, you iterate your existant records and mark the corresponding contact
for(var i=0;i<results.length;i++){
obj[results[i].phone].exists = true;
}

mongoDB: Find missing documents in model tree structure with parent reference

I have some documents which are organized in a model tree structure (depth is variable!). Unfortunately some documents are missing and I need to find those broken chains. As you can see the last document in that chain has always the target field. This is the starting point and I have to look upwards using parent. The last element in that chain has always the field type.
{
"_id" : "K7NSxNEnNSr9nCszR",
"title" : "title",
"type" : "book",
"ancestors" : [ ]
}
{
"_id" : "diyvwYz66yoTCTt9L",
"field" : "something",
"parent" : "K7NSxNEnNSr9nCszR",
"ancestors" : [
"K7NSxNEnNSr9nCszR"
]
}
{
"_id" : "diyvwYz66yoTCTt9L",
"field" : "anything",
"target" : "D2YuXtM6Gzt4eWaW2",
"parent" : "QWvdAyftSGANM3zy8",
"ancestors" : [
"K7NSxNEnNSr9nCszR",
"QWvdAyftSGANM3zy8"
]
}
What I need to know is if any parent is missing or if the last element (=type existing) is missing.
var broken = [];
Collection.find({ target: { $exists: true }}).forEach(function(element) {
var startDocID = element._id;
if (Collection.find({ _id: element.parent }).count() === 0)
broken.push(startDocID);
});
console.log(broken);
But this isn't working well as I need to use a loop to get upwards until the top document (= type existing).
You're talking about recursion here if you need to go down the tree, so you probably need to write a recursive search function
var broken = [];
Collection.find({ target: { $exists: true }}).forEach(function(element) {
function recurse(e) {
var startDocID = e._id;
var nodes = Collection.find({ _id: e.parent });
if (node.count() === 0)
{broken.push(startDocID);}
else {
nodes.fetch().forEach(node) {
recurse(node)
}
}
recurse(element);
}
});
or something of that sort... (hard to debug without the data)

MongoJS add to existing array

I am trying to add to an existing array in my mongoDB. Here is what I have, but it is of course incorrect because all the data gets wiped out after it tries to add it:
db.cardKeeper.update(
{_id: ObjectId('5621c5ac30895e5776e4d1ea')},
{
$push:{'cardKeeperApp.appData.cardDecks':deckObject}
}
)
deckObject which is the object I am trying to add to the array looks like this
var deckObject = {
name: productName,
searchName: productItem,
price:{
purchasePrice: productCost,
averageWorth: priceAverageFixed,
lowWorth: lowestSoldAmount,
highWorth: highestSoldAmount
}
}
and as you can see cardKeeperApp.appData.cardDecks is my array which holds more info that looks just like deckObject
If it helps here is the full object, I am trying to add to the cardDecks array. I have marked fields as null
{
"_id" : ObjectId("5635ddf82f4c220f4f932af2"),
"cardKeeperApp" : {
"appData" : {
"cardDecks" : [
{
"name" : "Some Name",
"searchName" : "Some+Name",
"price" : {
"purchasePrice" : null,
"averageWorth" : null,
"lowWorth" : null,
"highWorth" : null
}
}
],
"allDeckTotalWorth" : null
}
}
}
I found the solution. findAndModify by query:{_id:ObjectId} and then update and push:
db.cardKeeper.findAndModify({query:{_id: ObjectId('5635ddf82f4c220f4f932af2')},
update: {$push:{'cardKeeperApp.appData.cardDecks': deckObject}},
new:true}, function (err, doc) {
res.json(doc);
});

Mongo doesn't accept insertion of duplicate usernames

I need mongo to accept duplicate usernames because it is possible that you might have the same username for a different site, I have my code like this.
_(data)
.forEach(function (a, key) {
jobs['insert_' + a] = function (callback) {
mongo.open(config.MONGO_DB)
.collection('usernames')
.insert({
username: a,
indic: key,
favorites: ''
}, function (err, result) {
if (err) {
return next(err);
}
callback();
});
};
}
.commit();
async.parallel(jobs, send_response);
and I only get this one line as a result
{ "_id" : ObjectId("5592724901c01a6ca6b76a6a"), "username" : "asd", "indic" : "twitch", "favorites" : "" }
and the data I am passing is:
data = {twitch: 'asd', hitbox: 'asd', dailymotion: 'asd'}
Shouldn't I have something like this?
`{ "_id" : ObjectId("5592724901c01a6ca6b76axx"), "username" : "asd", "indic" : "twitch", "favorites" : "" }
{ "_id" : ObjectId("5592724901c01a6ca6b76axx"), "username" : "asd", "hitbox" : "twitch", "favorites" : "" }
{ "_id" : ObjectId("5592724901c01a6ca6b76axx"), "username" : "asd", "dailymotion" : "twitch", "favorites" : "" }
I am using this as my async function.
Your a variable is the one that is duplicated, so you keep adding the same key to jobs (namely insert_asd).
If you don't necessarily need to refer to the specific insert actions in the results, you can make jobs an array instead of an object:
var jobs = _(data).map(function(a, key) {
return function(callback) {
....
};
}).value();
However, it may be possible with your MongoDB driver to add the documents in one go, instead of separately. The official MongoDB driver supports arrays of documents using insertMany(), for instance.

Categories

Resources