add subitems to meteor document - mongodb

I have a meteor collection "list" that has the following data structure.
"list" : [
{
"_id" : "id",
"author" : "authorId",
"createdOn" : "DateTime",
"description" : "description",
"items" : [
{
"item1" : {
"itemComplete" : "Boolean",
"itemName" : "item name",
"itemDescription" : "item description",
}
},
{
"item2" : {
"itemComplete" : "Boolean",
"itemName" : "item name",
"itemDescription" : "item description",
}
}
],
Users will be able to add arbitrary number of list items. I am trying to figure out how to add itemX programmatically. E.g. I have the following code (which does not work) that gives an idea of what I am trying to accomplish.
var currentItemCount = Lists.find({_id:_currentListId, items:{}}).count() + 1;
var newItemNum = "item" + currentItemCount;
var newListItem = $("#list-item").val();
Lists.update({_id:_currentListId},{$push : {items:{newItemNum:{itemName:newListItem}}}});
I would appreciate any suggestions or hints to help me fix my code. Please let me know if I am missing some information.
Thanks in advance.
Kamal

Give something like this a try:
// fetch the current list
var list = Lists.findOne(_currentListId);
// find the number of existing items and handle the case where there are none
var numItems = (list.items || []).length;
// the the next item key will be one more than the length
var itemKey = 'item' + (numItems + 1);
// extract the item name from a form
var itemValue = {itemName: $('#list-item').val()};
// you can't use varaiable names as keys in object literals
// so we have to use bracket notation
item = {};
item[itemKey] = itemValue;
// push the new item onto the list of items
Lists.update(_currentListId, {$push: {items: item}});

Related

How to find an index array inside the MongoDB document

I have one collection with this document format:
{
"_id" : ObjectId("5c51fe3a6abdf0e5cd78f658"),
"0" : {
"id" : 1,
"name" : "carlos"
},
"1" : {
"id" : 2,
"name" : "foo"
},
"2" : {
"id" : 3,
"name" : "Jhon Doe"
},
"3" : {
"id" : 4,
"name" : "Max"
}
}
the only way to access the properties was doing a foreach loop and another for in inside.
db.getCollection('tutorial').find({}).forEach( (users) => {
for(user in users){
print("ID-> " + users[user].id, " Name->" + users[user].name);
}
});
But I can only print the results, there is another way to return a value using find ?
Thanks in advance.
You have to split up your operations. Get the collection first and then run a function to return the value you wish:
let collection = db.getCollection('tutorial').find({});
let name = () => {collection.forEach( (users) => {
for(user in users){
if(users[user].name == "foo"){
return ("ID-> " + users[user].id, " Name->" + users[user].name);
}
}
})};
or simply create a variable and set it when you run the loops
let name;
db.getCollection('tutorial').find({}).forEach( (users) => {
for(user in users){
name = ("ID-> " + users[user].id, " Name->" + users[user].name);
}
});
or something similar
Though all of these scenarios seem like a strange way to handle a mongo collection. I would definitely recommend restructuring your collection if you can't access the data using regular find method.

Display items from MongoDB to FrontEnd

I have a nested array in MongoDB database that I wish to display on the frontend using Jade and Express.
I am having some trouble displaying them:
This is the nested items I wish to display:
MongoDB:
{
"_id" : ObjectId("5c3343913d1e1323111fce6f"),
"title" : "Projecten",
"__v" : 0,
"sub_items" : [
{
"title" : "item1"
},
{
"title" : "item2"
}
]
}
Mongoose Model:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var menuItems = new mongoose.Schema({
sub_items : {
title: String
}
}, {collection: 'menu_items'});
module.exports = mongoose.model("menu_items", menuItems);
I post the nested items with Express like this:
postController.updateSubItems = function(req,res,item) {
var id = req.body.id;
var saveData = {
title: req.body.sub_item
};
item.update({_id: id}, {$addToSet:{sub_items: saveData}}, (err, result) => {
});
};
Display in jade like this:
each item in data
p #{item.sub_items}
Eventually it comes out like this:
item1,item2
Like a string, though I want to display them like single items
Try below code, as per your sub_items object
each item in [{sub_items:'sub_item_1'}]
p=item.sub_items
Paste above code into this editor
Not sure if there's a more elegant way to do this in Jade, but I just used the editor suggested by #iamwebkalakaar, tested the following snippet and it appears to print correctly:
each item in [{"sub_items" : [{"title" : "item1"}, {"title" : "item2"}]}]
each subitem in item.sub_items
p=subitem.title
New snippet
- var data = { "title" : "Projecten", "__v" : 0, "sub_items" : [ { "title" : "item1" }, { "title" : "item2" } ] };
each subitem in data.sub_items
p=subitem.title

Mongo nested query with keys

Need help on MongoDB nested query. Below is my mongo collection.
Preference collection
{
"_id" : "user123",
"preferences" : {
"product-1" : {
"frequency" : "Weekly",
"details" : {
"email" : {
"value" : "On"
}
}
},
"product-2" : {
"preferencesFor" : "mpc-other",
"preferencesForType" : "Product",
"details" : {
"email" : {
"value" : "Off"
}
}
},
"product-3" : {
"preferencesFor" : "mpc-other",
"preferencesForType" : "Product",
"details" : {
"email" : {
"value" : "On"
}
}
}
}
}
Product Collection
{
"_id" : "product-1",
"name" : "Geo-Magazine"
}
{
"_id" : "product-2",
"name" : "History-Magazine"
}
{
"_id" : "product-3",
"name" : "Science-Magazine"
}
product-1, product-2... are keys from a Map.
The keys are stored in another collection Product Collection.
Can I create a nested query to cross-reference the product keys from another table?
I need the output in the below table format. Please suggest.
user123 product-1 email On
user123 product-2 email Off
user123 product-3 email On
I tried the below but can't get result. Please suggest.
var cursor = db.productSummary.find();
while(cursor.hasNext()){
var sku = cursor.next()._id;
var skuCol = "preferences."+sku+".details.email";
var skuVal = "preferences."+sku+".details.email.value";
db.marketingPreferences.find( {}, {_id:1, skuCol:1, skuVal:1});
}
> var myCursor = db.productSummary.find();
> while(myCursor.hasNext()){
var sku = myCursor.next()._id;
var skuCol = "preferences."+sku+".details.email";
var skuVal = "$preferences."+sku+".details.email.value";
var result = db.marketingPreferences.aggregate([{"$project":{"_id":1,value:skuVal,preferences:{$literal: sku}}}],{allowDiskUse: true});
while(result.hasNext()){
printjson(result.next());
}
}
Result
{ "_id" : "user123", "preferences" : "product-1", "value" : "On" }
{ "_id" : "user123", "preferences" : "product-2", "value" : "Off" }
{ "_id" : "user123", "preferences" : "product-3", "value" : "On" }
There's a difference between MongoDB and normal SQL DB. Firstly, when you query a MongoDB collection, it doesn't return a row as it will in a SQL db. What you get here is a document similar to JSON.
Also when you use preferences.product-1.details.email : 1 it wont return you the word 'email', rather it will return you the value ie. {"value" : "On" }.
Using this: db.preference.find({},{"_id":1,"preferences.product1.details.email.value":1})
you will be able to get two details which are user123 and On and you can get product-1 from your previous query. You can store these values in a variable and keep printing them to obtain the table necessary. Also you would need another cursor to store the result of the second second query that you would do.
Here's what your query will produce if it was single standalone query:
> db.preference.find({},{"_id":1,"preferences.product1.details.email.value":1})
.pretty()
{
"_id": "user123",
"preferences": {
"product-1": {
"details": {
"email": {
"value": "On"
}
}
}
}
}
public static void test(){
MongoCollection<Document> collection = getDatadase().getCollection("product");
MongoCollection<Document> pref = getDatadase().getCollection("pref");
List<Document> allDocList = collection.find().into(new ArrayList<Document>());
for(Document doc:allDocList){
System.out.println(doc.get("_id"));
String preferences = doc.get("_id")+"";
String sku = "$preferences."+preferences+".details.email.value";
Document aggregation = new Document().append("$project", new Document().append("_id", 1).append("value", sku));
List<Document> pipeline = new ArrayList<Document>();
pipeline.add(aggregation);
List<Document> aggList = pref.aggregate(pipeline).into(new ArrayList<Document>());
for(Document doc1:aggList){
System.out.println(doc1.append("preferences", preferences));
}
}
}
This Will return
product-1
Document{{_id=user123, value=On, preferences=product-1}}
product-2
Document{{_id=user123, value=Off, preferences=product-2}}
product-3
Document{{_id=user123, value=On, preferences=product-3}}

How to Create an index of a key in a map or item in a list in MongoDB

The following questions refer to my example.
How do I create an index for the ids in idsAndNames map?
I want to search these numbers: 7065362, 7064458, 7065003, 7064286...
How do I create an index for the strings in subTargets list?
I want to search these strings: ALL, ACTION, DRAMA...
My example:
{
"_id" : ObjectId("sdfsdfsdfsdfsdfsd910d41ad9"),
"targets" : {
"Superheroes" : {
"idsAndNames" : {
"7065362" : "Doctor Strange",
"7064458" : "Dr. Manhattan",
"7065003" : "Captain Atom",
"7064286" : "Hulk"
},
"subTargets" : [
"ALL",
"ACTION",
"DRAMA"
]
}
"BestSuperheroes" : {
"idsAndNames" : {
"7065362" : "Superman",
"7064458" : "Thor",
"7065003" : "Professor X",
"7064286" : "Batman"
},
"subTargets" : [
"ALL",
"SCIFI",
"CHICKFLICKS"
]
}
}
...
}
Before trying to create an index maybe you should review your schema, changing it to something like:
...
"Superheores" : [
{
"id": "7065362",
"name": "Doctor Strange"
}]
So you can use db.collection.ensureIndex({'targets.Superheroes.id': 1});. You won't be able to create an effective index if you have dynamic key names.
And for the text, you could try the text search index.

Updating an array of objects with a new key in mongoDB

Similar to this question
Barrowing the data set, I have something similar to this:
{
'user_id':'{1231mjnD-32JIjn-3213}',
'name':'John',
'campaigns':
[
{
'campaign_id':3221,
'start_date':'12-01-2012',
},
{
'campaign_id':3222,
'start_date':'13-01-2012',
}
]
}
And I want to add a new key in the campaigns like so:
{
'user_id':'{1231mjnD-32JIjn-3213}',
'name':'John',
'campaigns':
[
{
'campaign_id':3221,
'start_date':'12-01-2012',
'worker_id': '00000'
},
{
'campaign_id':3222,
'start_date':'13-01-2012',
'worker_id': '00000'
}
]
}
How to insert/update a new key into an array of objects?
I want to add a new key into every object inside the array with a default value of 00000.
I have tried:
db.test.update({}, {$set: {'campaigns.worker_id': 00000}}, true, true)
db.test.update({}, {$set: {campaigns: {worker_id': 00000}}}, true, true)
Any suggestions?
I'm supposing that this operation will occur once, so you can use a script to handle it:
var docs = db.test.find();
for(var i in docs) {
var document = docs[i];
for(var j in document.campaigns) {
var campaign = document.campaigns[j];
campaign.worker_id = '00000';
}
db.test.save(document);
}
The script will iterate over all documents in your collection then over all campaigns in each document, setting the *worker_id* property.
At the end, each document is persisted.
db.test.update({}, {$set: {'campaigns.0.worker_id': 00000}}, true, true
this will update 0 element.
if you want to add a new key into every object inside the array you should use:
$unwind
example:
{
title : "this is my title" ,
author : "bob" ,
posted : new Date() ,
pageViews : 5 ,
tags : [ "fun" , "good" , "fun" ] ,
comments : [
{ author :"joe" , text : "this is cool" } ,
{ author :"sam" , text : "this is bad" }
],
other : { foo : 5 }
}
unwinding tags
db.article.aggregate(
{ $project : {
author : 1 ,
title : 1 ,
tags : 1
}},
{ $unwind : "$tags" }
);
result:
{
"result" : [
{
"_id" : ObjectId("4e6e4ef557b77501a49233f6"),
"title" : "this is my title",
"author" : "bob",
"tags" : "fun"
},
{
"_id" : ObjectId("4e6e4ef557b77501a49233f6"),
"title" : "this is my title",
"author" : "bob",
"tags" : "good"
},
{
"_id" : ObjectId("4e6e4ef557b77501a49233f6"),
"title" : "this is my title",
"author" : "bob",
"tags" : "fun"
}
],
"OK" : 1
}
After you could write simple updaiting query.