I'm very new to MongoDB so forgive me if this question isn't worded correctly. I know how to insert into the database, and I also know that I can have a nested object and know how to install that. I have:
Questions.insert({ Order:1, Question: "What type of property is it?",
Answers: { Order: 1, Answer: "House" }});
I hope from the above statement you can see that I'm aiming to try and insert multiple answers for this question (this may be where I'm going wrong, is this the right approach?). So looking at the above statement, I thought that I could insert multiple answers as such:
Questions.insert({ Order:1, Question: "What type of property is it?",
Answers: [{ Order: 1, Answer: "House" },
{ Order: 2, Answer: "Flat" },
{ Order: 3, Answer: "Bungalow" },
{ Order: 4, Answer: "Maisonette }]
});
SyntaxError: Unexpected token ILLEGAL
You are missing a " at the end of Maisonette which is where the error is coming from.
{ Order: 4, Answer: "Maisonette }]
Otherwise your query is on the right track for inserting embedded documents.
Your answers sub-document is kind of acting like an array. There are two possibilities you could use to store multiple answers in each question:
1) Just use an array:
Questions.insert({order : 1,
question : "What type of property is it?",
answers : [ "House", "Flat", "Bungalow", "Maisonette" ]
});
2) The way MongoDB will sometimes internally store arrays is to simply use an ordinal as the key to each sub-document, like so:
Questions.insert({order : 1,
question : "What type of property is it?",
answers : {"1" : "House",
"2" : "Flat",
"3" : "Bungalow",
"4" : "Maisonette"}
});
Related
Before I explain my use case, I'd like to state that yes, I could change this application so that it would store things in a different manner or even split it into 2 collections for that matter. But that's not my intention, and I'd rather want to know if this is at all possible within MongoDB (since I am quite new to MongoDB). I can for sure work around this problem if I'd really need to, but rather looking for a method to achieve what I want (no I am not being lazy here, I really want to know a way to do this).
Let's get to the problem then.
I have a document like below:
{
"_id" : ObjectId("XXXXXXXXXXXXXXXXXXXXX"),
"userId" : "XXXXXXX",
"licenses" : [
{
"domain" : "domain1.com",
"addons" : [
{"slug" : "1"},
{"slug" : "2"}
]
},
{
"domain" : "domain2.com",
"addons" : [
{"slug" : "1"},
]
}
]
}
My goal is to check if a specific domain has a specific addon. When I use the below query to count the documents with domain: domain2.com and addon slug: 2 the result should be: 0. However with the below query it returns 1. I know that this is because the query is executed document wide and not just the license index that matched domain2.com. So my question is, how to do a sub $and (or however you'd call it)?
db.test.countDocuments(
{$and: [
{"licenses.domain": "domain2.com"},
{"licenses.addons.slug": "2"},
]}
)
Basically I am looking for something like this (below isn't working obviously), but below should return 0, not 1:
db.test.countDocuments(
{$and: [
{
"licenses.domain": "domain2.com",
$and: [
{ "licenses.addons.slug": "2"}
]
}
]}
)
I know there is $group and $filter operators, I have been trying many combinations to no avail. I am lost at this point, I feel like I am completely missing the logic of Mongo here. However I believe this must be relatively easy to accomplish with a single query (just not for me I guess).
I have been trying to find my answer on the official documentation and via stack overflow/google, but I really couldn't find any such use case.
Any help is greatly appreciated! Thanks :)
What you are describe is searching for a document whose array contains a single element that matches multiple criteria.
This is exactly what the $elemMatch operator does.
Try using this for the filter part:
{
licenses: {
$elemMatch: {
domain: "domain2.com",
"addons.slug": "2"
}
}
}
I am trying to teach myself Meteor and Mongo. I have a particular insertion inside my Meteor method that is driving me nuts.
My document object looks like this:
{
_id
name: "name",
stuff: {},
array: [
{
id: 0,
target:[
{
id: 0,
name: "1"
},{
id: 1,
name: "2"
}
]
},{
id: 1,
target:[
{
id: 0,
name: "A"
},{
id: 1,
name: "B"
}
]
}
],
}
I am trying to add objects into the target array, which is inside an object inside the array-array.
I have tried a number of different approaches over a few days based on some things I have seen here on stack overflow. The most recent attempt is:
Documents.update({_id: id, 'array.id': arrayId}, {$addToSet:{'array.$.target': objectToInsert}},{upsert: false, multi: false})
If anyone could point me in the right direction I would appreciate it.
I donot know the mongo query to do something like this but it can be done as below
let theArray=Document.findOne({_id:id}).array,
arrayOfIds=_.pluck(theArray,"id"),
index=_.indexOf(arrayOfIds,arrayId),
theArray[index].target.push(objectTobeInserted)
Now update the document with the modified array
Document.update({_id:id},{$set:{array:theArray})
If you donot understand _.pluck and _.indexOf, you can refer to underscorejs
Seems this could be an issue with where you are doing the update. If this is on the client, then see here:
Update an subdocument contained in an array contained in a MongoDB document
Solution is to move this to the server.
Also, you may want to look at the difference between $addToSet and $push here MongoDb: Difference between $push/$addtoset
If this is not on the client side and changing to push does not fix your issue, can you add to your question what the error is.
I have a collection with the following structure:
event_id: "id",
votedUp: 0,
votedDown: 0,
questions: [
{
title: "title"
desc: "desc"
type: "TEXT"
answers: []
},
{
title: "title"
desc: "desc"
type: "MULTIPLE"
answers: [
{
value: "ans1",
answered: 0
},
{
value: "ans2",
answered: 2
},
]
}
]
Important thing here: question doesn't make any sense without an Event, so it can't have it's own ID - they are identified by their properties within given Event.
This is some kind of questionnaire, mixed a little bit with survey.
I have two use cases:
User completes questionnaire.
For TEXT questions, I need to push submitted answers.
For multi/single choice I need to increment 'answered' field.
How can I achieve this WITHOUT changing the model using mongodb? I've found this issue and I'm quite terrified. It seems like there's no way to do this with one query.
Is it still the case? Any workarounds?
The only idea I have is to retrieve document from database, edit it and save again, but since mongo has nothing to do with transactions, it could be dangerous...
Has anybody used MongoDB's Array type to implement a stack?
I know that I can append to an Array like so:
db.blogposts.update( {_id:5}, {$push: {comments: {by: "Abe", text:"First"}}})
Here, the end of the array is the top of the stack... I don't see a way to implement this with the top of the stack at the zero'th index, but I'd love to be wrong.
And I know that I can peek at the last value of the the array like so:
db.blogposts.find( {_id:5}, {comments: {$slice:-1}})
With an implementation like this, can I "peek" at the top of the stack in a MongoDB update statement? That would give me the semantic, "push this item on the stack if the top of the stack is X". I need this to be an atomic operation!
Any advice appreciated. Thanks!
Unfortunately, there is currently no way to do this exactly as you have described.
As Chris Shain pointed out, https://jira.mongodb.org/browse/SERVER-2191 - "$push() to front of array" and similarly https://jira.mongodb.org/browse/SERVER-1824 - "Support for inserting into specific array index" would help, but these features are currently not slated for a specific release version.
As a possible work-around, you could add a field named "lastElement" (or equivalent) to your document, which contains a copy of the last element pushed to the array. In your update statement, you could then query against the "lastElement" value, and if it matches, simultaneously set it to the new value and push the same value to the array in a single, atomic operation.
For example:
> db.blogposts.save({_id:5, comments:[{by: "Abe", text:"First"}], lastElement:{by: "Abe", text:"First"}})
> db.blogposts.find().pretty()
{
"_id" : 5,
"comments" : [
{
"by" : "Abe",
"text" : "First"
}
],
"lastElement" : {
"by" : "Abe",
"text" : "First"
}
}
> db.blogposts.update({"lastElement.text":"First"}, {$set:{lastElement:{by: "Joe", text:"Second"}}, $push:{comments:{by: "Joe", text:"Second"}}})
> db.blogposts.find().pretty()
{
"_id" : 5,
"comments" : [
{
"by" : "Abe",
"text" : "First"
},
{
"by" : "Joe",
"text" : "Second"
}
],
"lastElement" : {
"by" : "Joe",
"text" : "Second"
}
}
>
As an alternative, you may consider the strategy outlined in the "Update if Current" section of the "Atomic Operations" documentation: http://www.mongodb.org/display/DOCS/Atomic+Operations
I realize these are work-arounds and not ideal solutions. Hopefully the above will help you to accomplish your goal, or at least provide some food for thought for you to come up with a different solution. If you do, please share it here so that any members of the Community who may be experiencing similar issues may have the benefit of your experience. Thanks.
Looks like as of mongoDB v2.6, this is now supported via the $position operator: http://docs.mongodb.org/manual/reference/operator/update/position/
db.blogposts.update(
{_id:5}
, {$push:
{comments:
{$each: {by: "Abe", text:"First"}
, $position:0 }
}
}
);
I have a database of person documents. Each has a field named photos, which is an array of photo documents. I would like to add a new 'reviewed' flag to each of the photo documents and initialize it to false.
This is the query I am trying to use:
db.person.update({ "_id" : { $exists : true } }, {$set : {photos.reviewed : false} }, false, true)
However I get the following error:
SyntaxError: missing : after property id (shell):1
Is this possible, and if so, what am I doing wrong in my update?
Here is a full example of the 'person' document:
{
"_class" : "com.foo.Person",
"_id" : "2894",
"name" : "Pixel Spacebag",
"photos" : [
{
"_id" : null,
"thumbUrl" : "http://site.com/a_s.jpg",
"fullUrl" : "http://site.com/a.jpg"
},
{
"_id" : null,
"thumbUrl" : "http://site.com/b_s.jpg",
"fullUrl" : "http://site.com/b.jpg"
}]
}
Bonus karma for anyone who can tell me a cleaner why to update "all documents" without using the query { "_id" : { $exists : true } }
For those who are still looking for the answer it is possible with MongoDB 3.6 with the all positional operator $[] see the docs:
db.getCollection('person').update(
{},
{ $set: { "photos.$[].reviewed" : false } },
{ multi: true}
)
Is this possible, and if so, what am I doing wrong in my update?
No. In general MongoDB is only good at doing updates on top-level objects.
The exception here is the $ positional operator. From the docs: Use this to find an array member and then manipulate it.
However, in your case you want to modify all members in an array. So that is not what you need.
Bonus karma for anyone who can tell me a cleaner why to update "all documents"
Try db.coll.update(query, update, false, true), this will issue a "multi" update. That last true is what makes it a multi.
Is this possible,
You have two options here:
Write a for loop to perform the update. It will basically be a nested for loop, one to loop through the data, the other to loop through the sub-array. If you have a lot of data, you will want to write this is your driver of choice (and possibly multi-thread it).
Write your code to handle reviewed as nullable. Write the data such that if it comes across a photo with reviewed undefined then it must be false. Then you can set the field appropriately and commit it back to the DB.
Method #2 is something you should get used to. As your data grows and you add fields, it becomes difficult to "back-port" all of the old data. This is similar to the problem of issuing a schema change in SQL when you have 1B items in the DB.
Instead just make your code resistant against the null and learn to treat it as a default.
Again though, this is still not the solution you seek.
You can do this
(null, {$set : {"photos.reviewed" : false} }, false, true)
The first parameter is null : no specification = any item in the collection.
"photos.reviewed" should be declared as string to update subfield.
You can do like this:
db.person.update({}, $set:{name.surname:null}, false, true);
Old topic now, but this just worked fine with Mongo 3.0.6:
db.users.update({ _id: ObjectId("55e8969119cee85d216211fb") },
{ $set: {"settings.pieces": "merida"} })
In my case user entity looks like
{ _id: 32, name: "foo", ..., settings: { ..., pieces: "merida", ...} }