mongoose cannot save subdocument array after findOne - mongodb

I am trying to do something like this:
Industry.findOne({_id: id}).exec(function(err, industry){
industry.stats = _.extend(industry.stats, stats); //.......(1)
industry.save(function(err) {
// nothing is saved
});
});
The console.log of industry.stats in (1) is
[{ stat_id: 545080c8e4e88b1d5a7a6d1b}{ stat_id: 54526ca6b294096d33ca6b36 }]
This is not working, apparently the industry.stats is not an object array and misses a comma in between the two objects. (am I stating this correctly?)
If I assign industry.stats directly like this
[{stat_id: 545080c8e4e88b1d5a7a6d1b}, {stat_id: 54526ca6b294096d33ca6b36}]
Then it's working. Is there something I need to do to convert (1) to an object array first? I tried lean() and toObject()...etc but I got no luck. Am I missing something?

Lodash extend will assign own enumerable properties of source object to the destination object. In this case array properties of the source (stats) are copied to industry.stats. This will not work for arrays.
You'll have to update the array via array functions (push, pull,...) or set the field directly.

Related

Meteor, mongodb - accessing an object inside an array

Alright, so I have a collection called Polls. Inside the Polls "table" there is an attribute called choiceObjects which is an array of objects. Each object inside this array has its own attributes. What I need to do is update one of the attributes there. Ill give you a screen shot so you can better visualise what Im talking about
As you can see the choice objects have attributes like body, country etc. There is another attribute called pollid which is set to optional and therefore you cant see it right now. I need to update this pollid attribute now that I have acess to the pollid
Polls.update(
{ _id: pollId },
{ "$set": { "choiceObjects": { pollid: pollId } } }
); //this is kind of what Im trying to do but this isnt right
Since then... I have further tried the following :
var selectedpoll = Polls.findOne(pollId);
console.log(selectedpoll);
//Polls.update( selectedpoll, {"$set"{'choiceObjects.$.pollId':pollId}},false, true );
but when i try that i get the error : the positional operator did not find the match needed from the query. unexpanded update: choiceObjects.$.pollId
If I understand your objective correctly, you want to update (or add) pollid to all objects in the choiceObjects array. Unfortunately $, $push, $addToSet only work with single elements AFAIK.
This might not be what you are looking for but one possible and very obvious way to approach this problem would be to update the entire array in the collection i.e.
var choiceObjects = Polls.findOne({_id: pollId}).choiceObjects;
for (var i = 0; i < choiceObjects.length; i++) {
choiceObjects[i].pollid = pollid;
}
Polls.update({_id: pollid}, {choiceObjects: choiceObjects});

How to concatenate strings inside a MongoDB $set

I have a rather complex MongoDB Operator that uses a where to look through multiple users to see if they have a certain value, and if so it changes the value of it. My problem is that the value it checks for can be different for different cases, so my $set would require me to add strings together to get the property that I would change. This is what I mean:
users.update({$where:function() {
return this.profile.chatInfo.subscribedRooms.hasOwnProperty(findChatroom._id);
}},{$set: {"profile.chatInfo.subscribedRooms."+findChatroom._id:false}},{multi:true}
)
The only thing that does not work in that code is the part in the $set where I add "profile.chatInfo.subscribedRooms."+findChatroom._id
Another thing I have tried was making a variable that was equal to those strings added, and use the variable, but it also didn't work.
var addedString = "profile.chatInfo.subscribedRooms."+findChatroom._id;
users.update({$where:function() {
return this.profile.chatInfo.subscribedRooms.hasOwnProperty(findChatroom._id);
}},{$set: {addedString:false}},{multi:true}
)
What I am actually trying to do here, is that whenever a chat message is sent, this operator is ran. It looks for every user that is subscribed to a room, and sets the value to false. The value being true or false just refers to whether or not the user has read the chat. This is to be used for notifications.
Edit: My question is not a duplicate of this because the MongoDB set command works differently from simply changing the value of an object's property. To add onto that, MongoDB can't even use the notation of object[property], because the docs say the only way to access embedded fields is through dot notation.
Actually those links that #BlakesSeven provided will solve your problem. It should be something like this,
var addedString = "profile.chatInfo.subscribedRooms."+findChatroom._id;
var $set = {};
$set[addedString] = false;
users.update({$where:function() {
return this.profile.chatInfo.subscribedRooms.hasOwnProperty(findChatroom._id);
}}, { $set: $set }, { multi:true })

Referencing property in mongoDB by taking _id

I have a collection which have a document like this:
collection 1
{
_id: ObjectID(),
name: foo
}
I would get ObjectID of the above collection and copy into a document of another collection in order to reference correctly. Should I do simply:
db.collection1.find({name:"foo"},{_id:1})
EDIT
A call to find will return a cursor. Cursors works like an iterator in other languages. You can either attempt to find the first element in the cursor using the next() function and then get it's _id property or simplify your statement using findOne:
var x = db.collection1.findOne({name:"foo"}, {_id:1});
var id = x._id;
This is making an assumption that you are getting a document back from that query. You'll probably want to add a null check on x before grabbing the _id property.

Mongo - exclude entries in one collection from another find()

I have a local collection that logs when a user has viewed an entry. It stores the ID of the entry and the time it was viewed:
viewedDate = new Date();
notifications.insert({
'viewed': this.data._id,
'viewedDate': viewedDate
});
I want to exclude any of the 'viewed' ids in this collection from another find() (I basically want to count how many entries haven't been viewed)
How can I use the results of a notifications.find() to exclude results from another find()? If I assign the notifications.find() to a variable, it returns all kinds of stuff as an object.
edit
OK, so if I use fetch() I can restrict what comes back - can I do something with this in a find()?
myNotes = notifications.find({}, {fields: {'viewedDate' :0, _id:0}}).fetch();
This returns
[
Object
viewed: "HqYcCma3qKseHALyv"
__proto__: Object
]
Thanks to some invaluable help from garilla_ in the Meteor IRC, I got it working, solution as follows:
myViewedOffers = notifications.find({},{fields: {'viewed':1}}).fetch();
myViewedArray = myViewedOffers.map(function(viewed){return viewed.viewed});
offerCount = Offers.find({_id: {$nin: myViewedArray}}).count();

Using nodejs : mongodb find then add to Array

I made a simple db with a few users in it with mongodb and nodejs. Next im looping through the list and display the users in the list's names etc with sys.puts().
No I am adding the users to an Array() like this:
db.open(function(err, db) {
db.collection('users', function(err, collection) {
collection.find({}, {'sort':[['name', 1]]}, function(err, cursor) {
cursor.each(function(err, user) {
if(user != null) {
users[user._id] = { 'name':user.name, 'email': user.email };
sys.puts(">> Adding user to list... "+ user.name);
}
});
db.close();
});
});
});
Is this how I add the users to the array? Because the users.lenght = 0. Im a bit lost now
What you are doing is setting properties on the array object, that might be a bit confusing.
[] is both used for indexes and keys, that means in case of your array, users[0] will return the first element in the array, but users['blaid12'] will get/set the property blaid12' on the array object, that's like doingusers.blaid12`.
So in the end your array becomes more like a hashmap. The length property does not count the properties of the object, it counts the elements in the array.
You have a couple of ways of solving the issue:
Use an object {} and use the user ids as keys on that object, you'll have to keep track of the user count via another variable.
Use the array as an array by using users.push({'name':...}) to append elements to the array, if you need the userid too, then just add it to the object you push into the array.
Go with a mixed approach, use an array to push the values, and then an object to map the ids to the array indexes.